diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/internal/util/WorkingDaysToDaysConverter.java b/lib/taskana-core/src/main/java/pro/taskana/common/internal/util/WorkingDaysToDaysConverter.java index 37fde98df..87765e520 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/internal/util/WorkingDaysToDaysConverter.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/internal/util/WorkingDaysToDaysConverter.java @@ -8,14 +8,13 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.LongStream; -import java.util.stream.Stream; +import java.util.stream.LongStream.Builder; import pro.taskana.common.api.CustomHoliday; import pro.taskana.common.api.exceptions.InvalidArgumentException; @@ -37,6 +36,15 @@ public final class WorkingDaysToDaysConverter { private static boolean germanHolidaysEnabled; private static boolean corpusChristiEnabled; // Fronleichnam private static Set customHolidays = new HashSet<>(); + private static Set germanHolidays = + new HashSet<>( + Arrays.asList( + CustomHoliday.of(1, 1), // new year + CustomHoliday.of(1, 5), // labour day + CustomHoliday.of(3, 10), // german unity + CustomHoliday.of(25, 12), // Christmas + CustomHoliday.of(26, 12) // Christmas + )); private Instant referenceDate; private LocalDate easterSunday; @@ -127,7 +135,7 @@ public final class WorkingDaysToDaysConverter { return instant.plus(Duration.ofDays(days)); } - /** counts working days between two dates, inclusive for both margins. */ + /** counts working days between two dates, exclusive for both margins. */ public boolean hasWorkingDaysInBetween(Instant left, Instant right) { long days = Duration.between(left, right).abs().toDays(); Instant firstInstant = left.isBefore(right) ? left : right; @@ -155,28 +163,25 @@ public final class WorkingDaysToDaysConverter { } public boolean isGermanHoliday(LocalDate date) { - // Fix and movable holidays that are valid throughout Germany: New years day, Labour Day, Day of - // German - // Unity, Christmas, - if (Stream.of(GermanFixHolidays.values()).anyMatch(day -> day.matches(date))) { + if (germanHolidays.contains(CustomHoliday.of(date.getDayOfMonth(), date.getMonthValue()))) { return true; } // Easter holidays Good Friday, Easter Monday, Ascension Day, Whit Monday. long diffFromEasterSunday = DAYS.between(easterSunday, date); - List offSets = - new ArrayList<>( - Arrays.asList( - OFFSET_GOOD_FRIDAY, - OFFSET_EASTER_MONDAY, - OFFSET_ASCENSION_DAY, - OFFSET_WHIT_MONDAY)); + Builder builder = + LongStream.builder() + .add(OFFSET_GOOD_FRIDAY) + .add(OFFSET_EASTER_MONDAY) + .add(OFFSET_ASCENSION_DAY) + .add(OFFSET_WHIT_MONDAY); if (corpusChristiEnabled) { - offSets.add(OFFSET_CORPUS_CHRISTI); + builder.add(OFFSET_CORPUS_CHRISTI); } - return offSets.contains(diffFromEasterSunday); + + return builder.build().anyMatch(c -> c == diffFromEasterSunday); } /** @@ -208,14 +213,6 @@ public final class WorkingDaysToDaysConverter { return LocalDate.of(year, 3, 22).plusDays((long) d + e); } - private int calculateDirection(long numberOfDays, ZeroDirection zeroDirection) { - if (numberOfDays == 0) { - return zeroDirection.getDirection(); - } else { - return numberOfDays >= 0 ? 1 : -1; - } - } - void refreshReferenceDate(Instant newReferenceDate) { int yearOfReferenceDate = LocalDateTime.ofInstant(referenceDate, ZoneId.systemDefault()).getYear(); @@ -227,14 +224,21 @@ public final class WorkingDaysToDaysConverter { this.referenceDate = newReferenceDate; } + private int calculateDirection(long numberOfDays, ZeroDirection zeroDirection) { + if (numberOfDays == 0) { + return zeroDirection.getDirection(); + } else { + return numberOfDays >= 0 ? 1 : -1; + } + } + @Override public String toString() { - return "WorkingDaysToDaysConverter{" - + "dateCreated=" + return "WorkingDaysToDaysConverter [referenceDate=" + referenceDate + ", easterSunday=" + easterSunday - + '}'; + + "]"; } private enum ZeroDirection { @@ -251,25 +255,4 @@ public final class WorkingDaysToDaysConverter { return direction; } } - - /** Enumeration of German holidays. */ - private enum GermanFixHolidays { - NEWYEAR(1, 1), - LABOURDAY(5, 1), - GERMANUNITY(10, 3), - CHRISTMAS1(12, 25), - CHRISTMAS2(12, 26); - - private final int month; - private final int day; - - GermanFixHolidays(int month, int day) { - this.month = month; - this.day = day; - } - - public boolean matches(LocalDate date) { - return date.getDayOfMonth() == day && date.getMonthValue() == month; - } - } } diff --git a/lib/taskana-data/src/main/resources/sql/sample-data/workbasket.sql b/lib/taskana-data/src/main/resources/sql/sample-data/workbasket.sql index 1db97e67a..862c93a92 100644 --- a/lib/taskana-data/src/main/resources/sql/sample-data/workbasket.sql +++ b/lib/taskana-data/src/main/resources/sql/sample-data/workbasket.sql @@ -20,13 +20,13 @@ INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000014', 'USER INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000015', 'USER_3_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1 Domain B', 'DOMAIN_B', 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , 'owner0815' , 'ABCABC' , 'cust2' , 'cust3' , 'cust4' , 'orgl1' , 'orgl2' , 'orgl3' , 'orgl4' , false ); -- Workbaskets for sorting test -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000900', 'sort001' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxet0' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000901', 'Sort002' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Basxet1' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000902', 'sOrt003' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'bAsxet2' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000903', 'soRt004' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'baSxet3' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000904', 'sorT005' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basXet4' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000905', 'Sort006' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxEt5' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000906', 'SOrt007' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxeT6' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000907', 'SoRt008' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BAsxet7' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000908', 'SorT009' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BaSxet8' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000909', 'Sort010' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BasXet9' , 'DOM_XY' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000900', 'sort001' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxet0' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000901', 'Sort002' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Basxet1' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000902', 'sOrt003' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'bAsxet2' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000903', 'soRt004' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'baSxet3' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000904', 'sorT005' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basXet4' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000905', 'Sort006' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxEt5' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000906', 'SOrt007' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxeT6' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000907', 'SoRt008' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BAsxet7' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000908', 'SorT009' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BaSxet8' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000909', 'Sort010' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BasXet9' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'Max' , '' , '' , '' , '' , '' , '' , '' , '' , false ); diff --git a/lib/taskana-data/src/main/resources/sql/test-data/workbasket.sql b/lib/taskana-data/src/main/resources/sql/test-data/workbasket.sql index de96df0fe..2885a605a 100644 --- a/lib/taskana-data/src/main/resources/sql/test-data/workbasket.sql +++ b/lib/taskana-data/src/main/resources/sql/test-data/workbasket.sql @@ -18,13 +18,13 @@ INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000014', 'USER INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000015', 'USER_3_2', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1 Domain B', 'DOMAIN_B', 'PERSONAL', 'PPK User 1 KSC 1 Domain B', 'owner0815', 'ABCABC', 'cust2', 'cust3', 'cust4', 'orgl1', 'orgl2', 'orgl3', 'orgl4', FALSE); -- Workbaskets for sorting test -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000900', 'sort001', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxet0', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000901', 'Sort002', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Basxet1', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000902', 'sOrt003', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'bAsxet2', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000903', 'soRt004', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'baSxet3', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000904', 'sorT005', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basXet4', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000905', 'Sort006', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxEt5', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000906', 'SOrt007', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxeT6', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000907', 'SoRt008', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BAsxet7', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000908', 'SorT009', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BaSxet8', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000909', 'Sort010', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BasXet9', 'DOM_XY', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000900', 'sort001', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxet0', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000901', 'Sort002', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Basxet1', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000902', 'sOrt003', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'bAsxet2', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000903', 'soRt004', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'baSxet3', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000904', 'sorT005', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basXet4', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000905', 'Sort006', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxEt5', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000906', 'SOrt007', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxeT6', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000907', 'SoRt008', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BAsxet7', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000908', 'SorT009', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BaSxet8', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000909', 'Sort010', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BasXet9', 'DOMAIN_A', 'TOPIC', 'Lorem ipsum dolor sit amet.', 'Max', '', '', '', '', '', '', '', '', FALSE); diff --git a/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/RestHelper.java b/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/RestHelper.java index 48b015352..00a17c4e4 100644 --- a/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/RestHelper.java +++ b/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/RestHelper.java @@ -3,12 +3,16 @@ package pro.taskana; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; +import java.util.Collections; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; +import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.mediatype.hal.Jackson2HalModule; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @@ -67,9 +71,13 @@ public class RestHelper { mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); mapper.registerModule(new Jackson2HalModule()); + mapper + .registerModule(new ParameterNamesModule()) + .registerModule(new Jdk8Module()) + .registerModule(new JavaTimeModule()); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); - converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json")); + converter.setSupportedMediaTypes(Collections.singletonList(MediaTypes.HAL_JSON)); converter.setObjectMapper(mapper); RestTemplate template = new RestTemplate(); diff --git a/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/jobs/AsyncUpdateJobIntTest.java b/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/jobs/AsyncUpdateJobIntTest.java index 327761dfb..cc8d817c3 100644 --- a/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/jobs/AsyncUpdateJobIntTest.java +++ b/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/jobs/AsyncUpdateJobIntTest.java @@ -1,13 +1,13 @@ package pro.taskana.jobs; import static org.assertj.core.api.Assertions.assertThat; +import static pro.taskana.RestHelper.TEMPLATE; import com.fasterxml.jackson.databind.ObjectMapper; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -19,14 +19,12 @@ import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.web.client.RestTemplate; import pro.taskana.RestConfiguration; import pro.taskana.RestHelper; import pro.taskana.classification.api.models.Classification; import pro.taskana.classification.rest.assembler.ClassificationRepresentationModelAssembler; import pro.taskana.classification.rest.models.ClassificationRepresentationModel; -import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.rest.Mapping; import pro.taskana.task.api.models.Task; import pro.taskana.task.rest.assembler.TaskRepresentationModelAssembler; @@ -42,17 +40,25 @@ class AsyncUpdateJobIntTest { private static final String CLASSIFICATION_ID = "CLI:100000000000000000000000000000000003"; - @SuppressWarnings("checkstyle:DeclarationOrder") - static RestTemplate template; + private final ClassificationRepresentationModelAssembler + classificationRepresentationModelAssembler; + private final TaskRepresentationModelAssembler taskRepresentationModelAssembler; + private final JobScheduler jobScheduler; + private final RestHelper restHelper; + private final ObjectMapper mapper; - @Autowired ClassificationRepresentationModelAssembler classificationRepresentationModelAssembler; - @Autowired TaskRepresentationModelAssembler taskRepresentationModelAssembler; - @Autowired JobScheduler jobScheduler; - @Autowired RestHelper restHelper; - - @BeforeAll - static void init() { - template = RestHelper.TEMPLATE; + @Autowired + AsyncUpdateJobIntTest( + ClassificationRepresentationModelAssembler classificationRepresentationModelAssembler, + TaskRepresentationModelAssembler taskRepresentationModelAssembler, + JobScheduler jobScheduler, + RestHelper restHelper, + ObjectMapper mapper) { + this.classificationRepresentationModelAssembler = classificationRepresentationModelAssembler; + this.taskRepresentationModelAssembler = taskRepresentationModelAssembler; + this.jobScheduler = jobScheduler; + this.restHelper = restHelper; + this.mapper = mapper; } @Test @@ -60,10 +66,9 @@ class AsyncUpdateJobIntTest { // 1st step: get old classification : final Instant before = Instant.now(); - final ObjectMapper mapper = new ObjectMapper(); ResponseEntity response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_CLASSIFICATIONS_ID, CLASSIFICATION_ID), HttpMethod.GET, new HttpEntity(restHelper.getHeaders()), @@ -78,7 +83,7 @@ class AsyncUpdateJobIntTest { classification.setServiceLevel("P5D"); classification.setPriority(1000); - template.put( + TEMPLATE.put( restHelper.toUrl(Mapping.URL_CLASSIFICATIONS_ID, CLASSIFICATION_ID), new HttpEntity<>(mapper.writeValueAsString(classification), restHelper.getHeaders())); @@ -89,7 +94,7 @@ class AsyncUpdateJobIntTest { // verify the classification modified timestamp is after 'before' ResponseEntity repeatedResponse = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_CLASSIFICATIONS_ID, CLASSIFICATION_ID), HttpMethod.GET, new HttpEntity(restHelper.getHeaders()), @@ -150,17 +155,17 @@ class AsyncUpdateJobIntTest { } } - private void verifyTaskIsModifiedAfterOrEquals(String taskId, Instant before) - throws InvalidArgumentException { + private void verifyTaskIsModifiedAfterOrEquals(String taskId, Instant before) { ResponseEntity taskResponse = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS_ID, taskId), HttpMethod.GET, new HttpEntity<>(restHelper.getHeadersAdmin()), ParameterizedTypeReference.forType(TaskRepresentationModel.class)); TaskRepresentationModel taskRepresentationModel = taskResponse.getBody(); + assertThat(taskRepresentationModel).isNotNull(); Task task = taskRepresentationModelAssembler.toEntityModel(taskRepresentationModel); Instant modified = task.getModified(); diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/ClassificationDefinitionController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/ClassificationDefinitionController.java index 249a9b337..bac0a5a12 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/ClassificationDefinitionController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/ClassificationDefinitionController.java @@ -1,10 +1,12 @@ package pro.taskana.classification.rest; +import static pro.taskana.common.internal.util.CheckedFunction.wrap; + import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -13,6 +15,7 @@ import java.util.Set; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.hateoas.config.EnableHypermediaSupport; import org.springframework.http.ResponseEntity; @@ -37,6 +40,7 @@ import pro.taskana.common.api.exceptions.DomainNotFoundException; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.common.rest.Mapping; +import pro.taskana.common.rest.models.TaskanaPagedModel; /** Controller for Importing / Exporting classifications. */ @SuppressWarnings("unused") @@ -47,37 +51,41 @@ public class ClassificationDefinitionController { private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationDefinitionController.class); + private final ObjectMapper mapper; private final ClassificationService classificationService; - private final ClassificationRepresentationModelAssembler classificationRepresentationModelAssembler; + @Autowired ClassificationDefinitionController( + ObjectMapper mapper, ClassificationService classificationService, ClassificationRepresentationModelAssembler classificationRepresentationModelAssembler) { + this.mapper = mapper; this.classificationService = classificationService; this.classificationRepresentationModelAssembler = classificationRepresentationModelAssembler; } @GetMapping(path = Mapping.URL_CLASSIFICATIONDEFINITION) @Transactional(readOnly = true, rollbackFor = Exception.class) - public ResponseEntity> exportClassifications( + public ResponseEntity> exportClassifications( @RequestParam(required = false) String domain) throws ClassificationNotFoundException { LOGGER.debug("Entry to exportClassifications(domain= {})", domain); ClassificationQuery query = classificationService.createClassificationQuery(); List summaries = domain != null ? query.domainIn(domain).list() : query.list(); - List export = new ArrayList<>(); - for (ClassificationSummary summary : summaries) { - Classification classification = - classificationService.getClassification(summary.getKey(), summary.getDomain()); + TaskanaPagedModel pageModel = + summaries.stream() + .map(ClassificationSummary::getId) + .map(wrap(classificationService::getClassification)) + .collect( + Collectors.collectingAndThen( + Collectors.toList(), classificationRepresentationModelAssembler::toPageModel)); - export.add(classificationRepresentationModelAssembler.toModel(classification)); - } - - ResponseEntity> response = ResponseEntity.ok(export); + ResponseEntity> response = + ResponseEntity.ok(pageModel); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Exit from exportClassifications(), returning {}", response); } @@ -93,13 +101,13 @@ public class ClassificationDefinitionController { DomainNotFoundException, IOException { LOGGER.debug("Entry to importClassifications()"); Map systemIds = getSystemIds(); - List classificationsResources = + TaskanaPagedModel classificationsResources = extractClassificationResourcesFromFile(file); - checkForDuplicates(classificationsResources); + checkForDuplicates(classificationsResources.getContent()); Map childrenInFile = - mapChildrenToParentKeys(classificationsResources, systemIds); - insertOrUpdateClassificationsWithoutParent(classificationsResources, systemIds); + mapChildrenToParentKeys(classificationsResources.getContent(), systemIds); + insertOrUpdateClassificationsWithoutParent(classificationsResources.getContent(), systemIds); updateParentChildrenRelations(childrenInFile); ResponseEntity response = ResponseEntity.noContent().build(); LOGGER.debug("Exit from importClassifications(), returning {}", response); @@ -112,15 +120,15 @@ public class ClassificationDefinitionController { Collectors.toMap(i -> i.getKey() + "|" + i.getDomain(), ClassificationSummary::getId)); } - private List extractClassificationResourcesFromFile( - MultipartFile file) throws IOException { - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private TaskanaPagedModel + extractClassificationResourcesFromFile(MultipartFile file) throws IOException { return mapper.readValue( - file.getInputStream(), new TypeReference>() {}); + file.getInputStream(), + new TypeReference>() {}); } - private void checkForDuplicates(List classificationList) { + private void checkForDuplicates( + Collection classificationList) { List identifiers = new ArrayList<>(); Set duplicates = new HashSet<>(); for (ClassificationRepresentationModel classification : classificationList) { @@ -138,7 +146,7 @@ public class ClassificationDefinitionController { } private Map mapChildrenToParentKeys( - List classificationRepresentationModels, + Collection classificationRepresentationModels, Map systemIds) { LOGGER.debug("Entry to mapChildrenToParentKeys()"); Map childrenInFile = new HashMap<>(); @@ -159,8 +167,9 @@ public class ClassificationDefinitionController { } String parentKeyAndDomain = cl.getParentKey() + "|" + cl.getDomain(); - if ((!cl.getParentKey().isEmpty() && !cl.getParentKey().equals("") && ( - newKeysWithDomain.contains(parentKeyAndDomain) + if ((!cl.getParentKey().isEmpty() + && !cl.getParentKey().equals("") + && (newKeysWithDomain.contains(parentKeyAndDomain) || systemIds.containsKey(parentKeyAndDomain)))) { childrenInFile.put( classificationRepresentationModelAssembler.toEntityModel(cl), cl.getParentKey()); @@ -176,7 +185,7 @@ public class ClassificationDefinitionController { } private void insertOrUpdateClassificationsWithoutParent( - List classificationRepresentationModels, + Collection classificationRepresentationModels, Map systemIds) throws ClassificationNotFoundException, NotAuthorizedException, InvalidArgumentException, ClassificationAlreadyExistException, DomainNotFoundException, ConcurrencyException { @@ -197,8 +206,8 @@ public class ClassificationDefinitionController { updateExistingClassification(classificationRepresentationModel, systemId); } else { classificationService.createClassification( - classificationRepresentationModelAssembler - .toEntityModel(classificationRepresentationModel)); + classificationRepresentationModelAssembler.toEntityModel( + classificationRepresentationModel)); } } LOGGER.debug("Exit from insertOrUpdateClassificationsWithoutParent()"); diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationRepresentationModelAssembler.java index 71ce8ab96..8f11099cf 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationRepresentationModelAssembler.java @@ -2,10 +2,8 @@ package pro.taskana.classification.rest.assembler; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; -import java.time.Instant; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.hateoas.server.RepresentationModelAssembler; import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; @@ -17,6 +15,8 @@ import pro.taskana.classification.internal.models.ClassificationImpl; import pro.taskana.classification.rest.ClassificationController; import pro.taskana.classification.rest.models.ClassificationRepresentationModel; import pro.taskana.common.api.exceptions.SystemException; +import pro.taskana.common.rest.assembler.TaskanaPagingAssembler; +import pro.taskana.common.rest.models.TaskanaPagedModelKeys; /** * Transforms {@link Classification} to its resource counterpart {@link @@ -24,13 +24,12 @@ import pro.taskana.common.api.exceptions.SystemException; */ @Component public class ClassificationRepresentationModelAssembler - implements RepresentationModelAssembler { + implements TaskanaPagingAssembler { final ClassificationService classificationService; @Autowired - public ClassificationRepresentationModelAssembler( - ClassificationService classificationService) { + public ClassificationRepresentationModelAssembler(ClassificationService classificationService) { this.classificationService = classificationService; } @@ -42,7 +41,8 @@ public class ClassificationRepresentationModelAssembler try { resource.add( WebMvcLinkBuilder.linkTo( - methodOn(ClassificationController.class).getClassification(classification.getId())) + methodOn(ClassificationController.class) + .getClassification(classification.getId())) .withSelfRel()); } catch (ClassificationNotFoundException e) { throw new SystemException("caught unexpected Exception.", e.getCause()); @@ -50,6 +50,11 @@ public class ClassificationRepresentationModelAssembler return resource; } + @Override + public TaskanaPagedModelKeys getProperty() { + return TaskanaPagedModelKeys.CLASSIFICATIONS; + } + public Classification toEntityModel( ClassificationRepresentationModel classificationRepresentationModel) { ClassificationImpl classification = @@ -61,12 +66,8 @@ public class ClassificationRepresentationModelAssembler BeanUtils.copyProperties(classificationRepresentationModel, classification); classification.setId(classificationRepresentationModel.getClassificationId()); - if (classificationRepresentationModel.getCreated() != null) { - classification.setCreated(Instant.parse(classificationRepresentationModel.getCreated())); - } - if (classificationRepresentationModel.getModified() != null) { - classification.setModified(Instant.parse(classificationRepresentationModel.getModified())); - } + classification.setCreated(classificationRepresentationModel.getCreated()); + classification.setModified(classificationRepresentationModel.getModified()); return classification; } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationSummaryRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationSummaryRepresentationModelAssembler.java index db7d34a20..1d2365edb 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationSummaryRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationSummaryRepresentationModelAssembler.java @@ -2,12 +2,9 @@ package pro.taskana.classification.rest.assembler; import static pro.taskana.common.rest.models.TaskanaPagedModelKeys.CLASSIFICATIONS; -import java.util.List; -import java.util.stream.Collectors; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.PagedModel.PageMetadata; -import org.springframework.hateoas.server.RepresentationModelAssembler; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; @@ -16,16 +13,16 @@ import pro.taskana.classification.api.models.ClassificationSummary; import pro.taskana.classification.internal.models.ClassificationImpl; import pro.taskana.classification.rest.models.ClassificationSummaryRepresentationModel; import pro.taskana.common.rest.Mapping; +import pro.taskana.common.rest.assembler.TaskanaPagingAssembler; import pro.taskana.common.rest.models.TaskanaPagedModel; +import pro.taskana.common.rest.models.TaskanaPagedModelKeys; import pro.taskana.resource.rest.PageLinks; -/** - * EntityModel assembler for {@link ClassificationSummaryRepresentationModel}. - */ +/** EntityModel assembler for {@link ClassificationSummaryRepresentationModel}. */ @Component public class ClassificationSummaryRepresentationModelAssembler - implements - RepresentationModelAssembler { + implements TaskanaPagingAssembler< + ClassificationSummary, ClassificationSummaryRepresentationModel> { private final ClassificationService classificationService; @@ -51,15 +48,16 @@ public class ClassificationSummaryRepresentationModelAssembler BeanUtils.copyProperties(resource, classification); return classification.asSummary(); } - + + @Override + public TaskanaPagedModelKeys getProperty() { + return CLASSIFICATIONS; + } + @PageLinks(Mapping.URL_CLASSIFICATIONS) + @Override public TaskanaPagedModel toPageModel( - List classificationSummaries, PageMetadata pageMetadata) { - return classificationSummaries.stream() - .map(this::toModel) - .collect( - Collectors.collectingAndThen( - Collectors.toList(), - list -> new TaskanaPagedModel<>(CLASSIFICATIONS, list, pageMetadata))); + Iterable entities, PageMetadata pageMetadata) { + return TaskanaPagingAssembler.super.toPageModel(entities, pageMetadata); } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/models/ClassificationRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/models/ClassificationRepresentationModel.java index ee8397c6e..621b52085 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/models/ClassificationRepresentationModel.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/models/ClassificationRepresentationModel.java @@ -1,28 +1,25 @@ package pro.taskana.classification.rest.models; +import java.time.Instant; + import pro.taskana.classification.api.models.Classification; -/** - * EntityModel class for {@link Classification}. - */ -public class ClassificationRepresentationModel - extends ClassificationSummaryRepresentationModel { +/** EntityModel class for {@link Classification}. */ +public class ClassificationRepresentationModel extends ClassificationSummaryRepresentationModel { private Boolean isValidInDomain; - private String created; // ISO-8601 - private String modified; // ISO-8601 + + private Instant created; // ISO-8601 + private Instant modified; // ISO-8601 private String description; - public ClassificationRepresentationModel() { - } + public ClassificationRepresentationModel() {} public ClassificationRepresentationModel(Classification classification) { super(classification); this.isValidInDomain = classification.getIsValidInDomain(); - this.created = - classification.getCreated() != null ? classification.getCreated().toString() : null; - this.modified = - classification.getModified() != null ? classification.getModified().toString() : null; + this.created = classification.getCreated(); + this.modified = classification.getModified(); this.description = classification.getDescription(); } @@ -30,23 +27,23 @@ public class ClassificationRepresentationModel return isValidInDomain; } - public void setIsValidInDomain(Boolean validInDomain) { - isValidInDomain = validInDomain; + public void setIsValidInDomain(Boolean isValidInDomain) { + this.isValidInDomain = isValidInDomain; } - public String getCreated() { + public Instant getCreated() { return created; } - public void setCreated(String created) { + public void setCreated(Instant created) { this.created = created; } - public String getModified() { + public Instant getModified() { return modified; } - public void setModified(String modified) { + public void setModified(Instant modified) { this.modified = modified; } @@ -57,55 +54,4 @@ public class ClassificationRepresentationModel public void setDescription(String description) { this.description = description; } - - @Override - public String toString() { - return "ClassificationResource [classificationId=" - + classificationId - + ", key=" - + key - + ", parentId=" - + parentId - + ", parentKey=" - + parentKey - + ", category=" - + category - + ", type=" - + type - + ", domain=" - + domain - + ", isValidInDomain=" - + isValidInDomain - + ", created=" - + created - + ", modified=" - + modified - + ", name=" - + name - + ", description=" - + description - + ", priority=" - + priority - + ", serviceLevel=" - + serviceLevel - + ", applicationEntryPoint=" - + applicationEntryPoint - + ", custom1=" - + custom1 - + ", custom2=" - + custom2 - + ", custom3=" - + custom3 - + ", custom4=" - + custom4 - + ", custom5=" - + custom5 - + ", custom6=" - + custom6 - + ", custom7=" - + custom7 - + ", custom8=" - + custom8 - + "]"; - } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/assembler/TaskanaPagingAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/assembler/TaskanaPagingAssembler.java new file mode 100644 index 000000000..beb8207d2 --- /dev/null +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/assembler/TaskanaPagingAssembler.java @@ -0,0 +1,29 @@ +package pro.taskana.common.rest.assembler; + +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import org.springframework.hateoas.PagedModel.PageMetadata; +import org.springframework.hateoas.RepresentationModel; +import org.springframework.hateoas.server.RepresentationModelAssembler; + +import pro.taskana.common.rest.models.TaskanaPagedModel; +import pro.taskana.common.rest.models.TaskanaPagedModelKeys; + +public interface TaskanaPagingAssembler> + extends RepresentationModelAssembler { + + TaskanaPagedModelKeys getProperty(); + + default TaskanaPagedModel toPageModel( + Iterable entities, PageMetadata pageMetadata) { + return StreamSupport.stream(entities.spliterator(), false) + .map(this::toModel) + .collect( + Collectors.collectingAndThen( + Collectors.toList(), l -> new TaskanaPagedModel<>(getProperty(), l, pageMetadata))); + } + + default TaskanaPagedModel toPageModel(Iterable entities) { + return toPageModel(entities, null); + } +} diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/models/TaskanaPagedModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/models/TaskanaPagedModel.java index eeefc09b9..96a082f0c 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/models/TaskanaPagedModel.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/models/TaskanaPagedModel.java @@ -17,26 +17,23 @@ import org.springframework.hateoas.RepresentationModel; * * @param The class of the paginated content */ -public class TaskanaPagedModel> +public class TaskanaPagedModel> extends RepresentationModel> { - @JsonIgnore - private TaskanaPagedModelKeys key; - @JsonIgnore - private Collection content; + @JsonIgnore private TaskanaPagedModelKeys key; + @JsonIgnore private Collection content; @JsonProperty(value = "page", access = Access.WRITE_ONLY) private PageMetadata metadata; @SuppressWarnings("unused") // needed for jackson - private TaskanaPagedModel() { - } + private TaskanaPagedModel() {} /** * Creates a new {@link TaskanaPagedModel} from the given content. * * @param property property which will be used for serialization. - * @param content must not be {@literal null}. + * @param content must not be {@literal null}. * @param metadata the metadata. Can be null. If null, no metadata will be serialized. */ public TaskanaPagedModel( @@ -46,6 +43,10 @@ public class TaskanaPagedModel> this.key = property; } + public TaskanaPagedModel(TaskanaPagedModelKeys property, Collection content) { + this(property, content, null); + } + public Collection getContent() { return Collections.unmodifiableCollection(content); } @@ -54,6 +55,10 @@ public class TaskanaPagedModel> return metadata; } + public TaskanaPagedModelKeys getKey() { + return key; + } + @JsonAnySetter private void deserialize(String propertyName, Collection content) { TaskanaPagedModelKeys.getEnumFromPropertyName(propertyName) diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/models/TaskanaPagedModelKeys.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/models/TaskanaPagedModelKeys.java index 2e12322c1..91050bf50 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/models/TaskanaPagedModelKeys.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/models/TaskanaPagedModelKeys.java @@ -12,7 +12,8 @@ public enum TaskanaPagedModelKeys { DISTRIBUTION_TARGETS("distributionTargets"), TASKS("tasks"), TASK_COMMENTS("taskComments"), - WORKBASKETS("workbaskets"); + WORKBASKETS("workbaskets"), + WORKBASKET_DEFINITIONS("workbasketDefinitions"); private static final Map PROPERTY_MAP = Arrays.stream(TaskanaPagedModelKeys.values()) diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/AttachmentSummaryRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/AttachmentSummaryRepresentationModelAssembler.java index 2d97556bb..9cf16ee25 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/AttachmentSummaryRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/AttachmentSummaryRepresentationModelAssembler.java @@ -1,23 +1,60 @@ package pro.taskana.task.rest.assembler; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.server.RepresentationModelAssembler; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; +import pro.taskana.classification.rest.assembler.ClassificationSummaryRepresentationModelAssembler; +import pro.taskana.task.api.TaskService; import pro.taskana.task.api.models.AttachmentSummary; +import pro.taskana.task.internal.models.AttachmentImpl; import pro.taskana.task.rest.models.AttachmentSummaryRepresentationModel; -/** - * EntityModel assembler for {@link AttachmentSummaryRepresentationModel}. - */ +/** EntityModel assembler for {@link AttachmentSummaryRepresentationModel}. */ @Component -public class AttachmentSummaryRepresentationModelAssembler implements - RepresentationModelAssembler { +public class AttachmentSummaryRepresentationModelAssembler + implements RepresentationModelAssembler< + AttachmentSummary, AttachmentSummaryRepresentationModel> { + + private final TaskService taskService; + private final ClassificationSummaryRepresentationModelAssembler classificationSummaryAssembler; + + @Autowired + public AttachmentSummaryRepresentationModelAssembler( + TaskService taskService, + ClassificationSummaryRepresentationModelAssembler classificationSummaryAssembler) { + this.taskService = taskService; + this.classificationSummaryAssembler = classificationSummaryAssembler; + } @NonNull @Override - public AttachmentSummaryRepresentationModel toModel( - @NonNull AttachmentSummary attachmentSummary) { - return new AttachmentSummaryRepresentationModel(attachmentSummary); + public AttachmentSummaryRepresentationModel toModel(@NonNull AttachmentSummary summary) { + AttachmentSummaryRepresentationModel repModel = new AttachmentSummaryRepresentationModel(); + repModel.setAttachmentId(summary.getId()); + repModel.setTaskId(summary.getTaskId()); + repModel.setCreated(summary.getCreated()); + repModel.setModified(summary.getModified()); + repModel.setReceived(summary.getReceived()); + repModel.setClassificationSummary( + classificationSummaryAssembler.toModel(summary.getClassificationSummary())); + repModel.setObjectReference(summary.getObjectReference()); + repModel.setChannel(summary.getChannel()); + return repModel; + } + + public AttachmentSummary toEntityModel(AttachmentSummaryRepresentationModel repModel) { + AttachmentImpl attachment = (AttachmentImpl) taskService.newAttachment(); + attachment.setId(repModel.getAttachmentId()); + attachment.setTaskId(repModel.getTaskId()); + attachment.setCreated(repModel.getCreated()); + attachment.setModified(repModel.getModified()); + attachment.setReceived(repModel.getReceived()); + attachment.setClassificationSummary( + classificationSummaryAssembler.toEntityModel(repModel.getClassificationSummary())); + attachment.setObjectReference(repModel.getObjectReference()); + attachment.setChannel(repModel.getChannel()); + return attachment; } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssembler.java index bc6cee2e8..d7d41aea9 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssembler.java @@ -3,12 +3,11 @@ package pro.taskana.task.rest.assembler; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; -import java.time.Instant; import java.util.Objects; import java.util.stream.Collectors; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport; +import org.springframework.hateoas.server.RepresentationModelAssembler; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; @@ -30,7 +29,7 @@ import pro.taskana.workbasket.rest.assembler.WorkbasketSummaryRepresentationMode */ @Component public class TaskRepresentationModelAssembler - extends RepresentationModelAssemblerSupport { + implements RepresentationModelAssembler { private final TaskService taskService; @@ -47,7 +46,6 @@ public class TaskRepresentationModelAssembler ClassificationSummaryRepresentationModelAssembler classificationAssembler, WorkbasketSummaryRepresentationModelAssembler workbasketSummaryRepresentationModelAssembler, AttachmentRepresentationModelAssembler attachmentAssembler) { - super(TaskController.class, TaskRepresentationModel.class); this.taskService = taskService; this.classificationAssembler = classificationAssembler; this.workbasketSummaryRepresentationModelAssembler @@ -68,8 +66,7 @@ public class TaskRepresentationModelAssembler return resource; } - public Task toEntityModel(TaskRepresentationModel resource) throws InvalidArgumentException { - validateTaskResource(resource); + public Task toEntityModel(TaskRepresentationModel resource) { TaskImpl task = (TaskImpl) taskService.newTask( @@ -77,24 +74,7 @@ public class TaskRepresentationModelAssembler task.setId(resource.getTaskId()); task.setExternalId(resource.getExternalId()); BeanUtils.copyProperties(resource, task); - if (resource.getCreated() != null) { - task.setCreated(Instant.parse(resource.getCreated())); - } - if (resource.getModified() != null) { - task.setModified(Instant.parse(resource.getModified())); - } - if (resource.getClaimed() != null) { - task.setClaimed(Instant.parse(resource.getClaimed())); - } - if (resource.getCompleted() != null) { - task.setCompleted(Instant.parse(resource.getCompleted())); - } - if (resource.getDue() != null) { - task.setDue(Instant.parse(resource.getDue())); - } - if (resource.getPlanned() != null) { - task.setPlanned(Instant.parse(resource.getPlanned())); - } + task.setClassificationSummary( classificationAssembler.toEntityModel( resource.getClassificationSummary())); @@ -113,20 +93,4 @@ public class TaskRepresentationModelAssembler return task; } - - private void validateTaskResource(TaskRepresentationModel resource) - throws InvalidArgumentException { - if (resource.getWorkbasketSummary() == null - || resource.getWorkbasketSummary().getWorkbasketId() == null - || resource.getWorkbasketSummary().getWorkbasketId().isEmpty()) { - throw new InvalidArgumentException( - "TaskResource must have a workbasket summary with a valid workbasketId."); - } - if (resource.getClassificationSummary() == null - || resource.getClassificationSummary().getKey() == null - || resource.getClassificationSummary().getKey().isEmpty()) { - throw new InvalidArgumentException( - "TaskResource must have a classification summary with a valid classification key."); - } - } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/AttachmentSummaryRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/AttachmentSummaryRepresentationModel.java index 3c3957796..2178b3313 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/AttachmentSummaryRepresentationModel.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/AttachmentSummaryRepresentationModel.java @@ -1,42 +1,39 @@ package pro.taskana.task.rest.models; +import java.time.Instant; import org.springframework.hateoas.RepresentationModel; import pro.taskana.classification.rest.models.ClassificationSummaryRepresentationModel; import pro.taskana.task.api.models.AttachmentSummary; import pro.taskana.task.api.models.ObjectReference; -/** - * EntityModel class for {@link AttachmentSummary}. - */ +/** EntityModel class for {@link AttachmentSummary}. */ public class AttachmentSummaryRepresentationModel extends RepresentationModel { protected String attachmentId; protected String taskId; - protected String created; - protected String modified; + protected Instant created; + protected Instant modified; + protected Instant received; protected ClassificationSummaryRepresentationModel classificationSummary; protected ObjectReference objectReference; protected String channel; - protected String received; - AttachmentSummaryRepresentationModel() { - } + // TODO: remove this constructor + public AttachmentSummaryRepresentationModel() {} + // TODO: remove this constructor public AttachmentSummaryRepresentationModel(AttachmentSummary attachmentSummary) { this.attachmentId = attachmentSummary.getId(); this.taskId = attachmentSummary.getTaskId(); - this.created = - attachmentSummary.getCreated() != null ? attachmentSummary.getCreated().toString() : null; - this.modified = - attachmentSummary.getModified() != null ? attachmentSummary.getModified().toString() : null; + this.created = attachmentSummary.getCreated(); + this.modified = attachmentSummary.getModified(); + this.received = attachmentSummary.getReceived(); this.classificationSummary = new ClassificationSummaryRepresentationModel(attachmentSummary.getClassificationSummary()); this.objectReference = attachmentSummary.getObjectReference(); this.channel = attachmentSummary.getChannel(); - this.received = - attachmentSummary.getReceived() != null ? attachmentSummary.getReceived().toString() : null; } public String getAttachmentId() { @@ -55,22 +52,30 @@ public class AttachmentSummaryRepresentationModel this.taskId = taskId; } - public String getCreated() { + public Instant getCreated() { return created; } - public void setCreated(String created) { + public void setCreated(Instant created) { this.created = created; } - public String getModified() { + public Instant getModified() { return modified; } - public void setModified(String modified) { + public void setModified(Instant modified) { this.modified = modified; } + public Instant getReceived() { + return received; + } + + public void setReceived(Instant received) { + this.received = received; + } + public ClassificationSummaryRepresentationModel getClassificationSummary() { return classificationSummary; } @@ -95,34 +100,4 @@ public class AttachmentSummaryRepresentationModel public void setChannel(String channel) { this.channel = channel; } - - public String getReceived() { - return received; - } - - public void setReceived(String received) { - this.received = received; - } - - @Override - public String toString() { - return "AttachmentSummaryResource [" - + "attachmentId= " - + this.attachmentId - + "taskId= " - + this.taskId - + "created= " - + this.created - + "modified= " - + this.modified - + "classificationSummaryResource= " - + this.classificationSummary - + "objectReference= " - + this.objectReference - + "channel= " - + this.channel - + "received= " - + this.received - + "]"; - } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/TaskSummaryRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/TaskSummaryRepresentationModel.java index 39998de67..04146264f 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/TaskSummaryRepresentationModel.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/TaskSummaryRepresentationModel.java @@ -1,5 +1,6 @@ package pro.taskana.task.rest.models; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -21,12 +22,12 @@ public class TaskSummaryRepresentationModel protected String taskId; protected String externalId; - protected String created; // ISO-8601 - protected String claimed; // ISO-8601 - protected String completed; // ISO-8601 - protected String modified; // ISO-8601 - protected String planned; // ISO-8601 - protected String due; // ISO-8601 + protected Instant created; // ISO-8601 + protected Instant claimed; // ISO-8601 + protected Instant completed; // ISO-8601 + protected Instant modified; // ISO-8601 + protected Instant planned; // ISO-8601 + protected Instant due; // ISO-8601 protected String name; protected String creator; protected String note; @@ -66,12 +67,12 @@ public class TaskSummaryRepresentationModel public TaskSummaryRepresentationModel(TaskSummary taskSummary) throws InvalidArgumentException { this.taskId = taskSummary.getId(); this.externalId = taskSummary.getExternalId(); - created = taskSummary.getCreated() != null ? taskSummary.getCreated().toString() : null; - claimed = taskSummary.getClaimed() != null ? taskSummary.getClaimed().toString() : null; - completed = taskSummary.getCompleted() != null ? taskSummary.getCompleted().toString() : null; - modified = taskSummary.getModified() != null ? taskSummary.getModified().toString() : null; - planned = taskSummary.getPlanned() != null ? taskSummary.getPlanned().toString() : null; - due = taskSummary.getDue() != null ? taskSummary.getDue().toString() : null; + created = taskSummary.getCreated(); + claimed = taskSummary.getClaimed(); + completed = taskSummary.getCompleted(); + modified = taskSummary.getModified(); + planned = taskSummary.getPlanned(); + due = taskSummary.getDue(); this.name = taskSummary.getName(); this.creator = taskSummary.getCreator(); this.note = taskSummary.getNote(); @@ -126,51 +127,51 @@ public class TaskSummaryRepresentationModel this.externalId = externalId; } - public String getCreated() { + public Instant getCreated() { return created; } - public void setCreated(String created) { + public void setCreated(Instant created) { this.created = created; } - public String getClaimed() { + public Instant getClaimed() { return claimed; } - public void setClaimed(String claimed) { + public void setClaimed(Instant claimed) { this.claimed = claimed; } - public String getCompleted() { + public Instant getCompleted() { return completed; } - public void setCompleted(String completed) { + public void setCompleted(Instant completed) { this.completed = completed; } - public String getModified() { + public Instant getModified() { return modified; } - public void setModified(String modified) { + public void setModified(Instant modified) { this.modified = modified; } - public String getPlanned() { + public Instant getPlanned() { return planned; } - public void setPlanned(String planned) { + public void setPlanned(Instant planned) { this.planned = planned; } - public String getDue() { + public Instant getDue() { return due; } - public void setDue(String due) { + public void setDue(Instant due) { this.due = due; } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/WorkbasketController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/WorkbasketController.java index c354eef66..741c0a5cc 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/WorkbasketController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/WorkbasketController.java @@ -42,7 +42,6 @@ import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; import pro.taskana.workbasket.api.models.Workbasket; import pro.taskana.workbasket.api.models.WorkbasketAccessItem; import pro.taskana.workbasket.api.models.WorkbasketSummary; -import pro.taskana.workbasket.rest.assembler.DistributionTargetRepresentationModelAssembler; import pro.taskana.workbasket.rest.assembler.WorkbasketAccessItemRepresentationModelAssembler; import pro.taskana.workbasket.rest.assembler.WorkbasketRepresentationModelAssembler; import pro.taskana.workbasket.rest.assembler.WorkbasketSummaryRepresentationModelAssembler; @@ -80,8 +79,7 @@ public class WorkbasketController extends AbstractPagingController { private final WorkbasketSummaryRepresentationModelAssembler workbasketSummaryRepresentationModelAssembler; - private final DistributionTargetRepresentationModelAssembler - distributionTargetRepresentationModelAssembler; + private final WorkbasketAccessItemRepresentationModelAssembler workbasketAccessItemRepresentationModelAssembler; @@ -90,15 +88,13 @@ public class WorkbasketController extends AbstractPagingController { WorkbasketService workbasketService, WorkbasketRepresentationModelAssembler workbasketRepresentationModelAssembler, WorkbasketSummaryRepresentationModelAssembler workbasketSummaryRepresentationModelAssembler, - DistributionTargetRepresentationModelAssembler distributionTargetRepresentationModelAssembler, WorkbasketAccessItemRepresentationModelAssembler workbasketAccessItemRepresentationModelAssembler) { this.workbasketService = workbasketService; this.workbasketRepresentationModelAssembler = workbasketRepresentationModelAssembler; this.workbasketSummaryRepresentationModelAssembler = workbasketSummaryRepresentationModelAssembler; - this.distributionTargetRepresentationModelAssembler = - distributionTargetRepresentationModelAssembler; + this.workbasketAccessItemRepresentationModelAssembler = workbasketAccessItemRepresentationModelAssembler; } @@ -236,7 +232,7 @@ public class WorkbasketController extends AbstractPagingController { workbasketService.getWorkbasketAccessItems(workbasketId); result = ResponseEntity.ok( - workbasketAccessItemRepresentationModelAssembler.toPageModel( + workbasketAccessItemRepresentationModelAssembler.toPageModelForSingleWorkbasket( workbasketId, accessItems, null)); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Exit from getWorkbasketAccessItems(), returning {}", result); @@ -268,7 +264,7 @@ public class WorkbasketController extends AbstractPagingController { ResponseEntity> response = ResponseEntity.ok( - workbasketAccessItemRepresentationModelAssembler.toPageModel( + workbasketAccessItemRepresentationModelAssembler.toPageModelForSingleWorkbasket( workbasketId, updatedWbAccessItems, null)); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Exit from setWorkbasketAccessItems(), returning {}", response); @@ -287,7 +283,8 @@ public class WorkbasketController extends AbstractPagingController { List distributionTargets = workbasketService.getDistributionTargets(workbasketId); TaskanaPagedModel distributionTargetListResource = - distributionTargetRepresentationModelAssembler.toPageModel(distributionTargets, null); + workbasketSummaryRepresentationModelAssembler + .toDistributionTargetPageModel(distributionTargets, null); ResponseEntity> result = ResponseEntity.ok(distributionTargetListResource); if (LOGGER.isDebugEnabled()) { @@ -317,7 +314,8 @@ public class WorkbasketController extends AbstractPagingController { workbasketService.getDistributionTargets(sourceWorkbasketId); ResponseEntity> response = ResponseEntity.ok( - distributionTargetRepresentationModelAssembler.toPageModel(distributionTargets, null)); + workbasketSummaryRepresentationModelAssembler + .toDistributionTargetPageModel(distributionTargets, null)); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Exit from getTasksStatusReport(), returning {}", response); } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/WorkbasketDefinitionController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/WorkbasketDefinitionController.java index 707036ddd..907060962 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/WorkbasketDefinitionController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/WorkbasketDefinitionController.java @@ -1,11 +1,12 @@ package pro.taskana.workbasket.rest; +import static pro.taskana.common.internal.util.CheckedFunction.wrap; + import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -14,6 +15,7 @@ import java.util.Set; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.hateoas.config.EnableHypermediaSupport; import org.springframework.http.ResponseEntity; @@ -29,6 +31,7 @@ import pro.taskana.common.api.exceptions.DomainNotFoundException; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.common.rest.Mapping; +import pro.taskana.common.rest.models.TaskanaPagedModel; import pro.taskana.workbasket.api.WorkbasketQuery; import pro.taskana.workbasket.api.WorkbasketService; import pro.taskana.workbasket.api.exceptions.InvalidWorkbasketException; @@ -53,33 +56,38 @@ public class WorkbasketDefinitionController { LoggerFactory.getLogger(WorkbasketDefinitionController.class); private final WorkbasketService workbasketService; - private final WorkbasketDefinitionRepresentationModelAssembler workbasketDefinitionAssembler; + private final ObjectMapper mapper; + @Autowired WorkbasketDefinitionController( WorkbasketService workbasketService, - WorkbasketDefinitionRepresentationModelAssembler workbasketDefinitionAssembler) { + WorkbasketDefinitionRepresentationModelAssembler workbasketDefinitionAssembler, + ObjectMapper mapper) { this.workbasketService = workbasketService; this.workbasketDefinitionAssembler = workbasketDefinitionAssembler; + this.mapper = mapper; } @GetMapping(path = Mapping.URL_WORKBASKETDEFIITIONS) @Transactional(readOnly = true, rollbackFor = Exception.class) - public ResponseEntity> exportWorkbaskets( - @RequestParam(required = false) String domain) - throws NotAuthorizedException, WorkbasketNotFoundException { + public ResponseEntity> + exportWorkbaskets(@RequestParam(required = false) String domain) { LOGGER.debug("Entry to exportWorkbaskets(domain= {})", domain); WorkbasketQuery workbasketQuery = workbasketService.createWorkbasketQuery(); List workbasketSummaryList = domain != null ? workbasketQuery.domainIn(domain).list() : workbasketQuery.list(); - List basketExports = new ArrayList<>(); - for (WorkbasketSummary summary : workbasketSummaryList) { - Workbasket workbasket = workbasketService.getWorkbasket(summary.getId()); - basketExports.add(workbasketDefinitionAssembler.toModel(workbasket)); - } - ResponseEntity> response = - ResponseEntity.ok(basketExports); + TaskanaPagedModel pageModel = + workbasketSummaryList.stream() + .map(WorkbasketSummary::getId) + .map(wrap(workbasketService::getWorkbasket)) + .collect( + Collectors.collectingAndThen( + Collectors.toList(), workbasketDefinitionAssembler::toPageModel)); + + ResponseEntity> response = + ResponseEntity.ok(pageModel); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Exit from exportWorkbaskets(), returning {}", response); } @@ -118,29 +126,26 @@ public class WorkbasketDefinitionController { InvalidArgumentException, WorkbasketAccessItemAlreadyExistException, ConcurrencyException { LOGGER.debug("Entry to importWorkbaskets()"); - ObjectMapper mapper = new ObjectMapper(); - mapper.enable(SerializationFeature.INDENT_OUTPUT); - mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - List definitions = + TaskanaPagedModel definitions = mapper.readValue( file.getInputStream(), - new TypeReference>() {}); + new TypeReference>() {}); // key: logical ID // value: system ID (in database) Map systemIds = workbasketService.createWorkbasketQuery().list().stream() .collect(Collectors.toMap(this::logicalId, WorkbasketSummary::getId)); - checkForDuplicates(definitions); + checkForDuplicates(definitions.getContent()); // key: old system ID // value: system ID Map idConversion = new HashMap<>(); // STEP 1: update or create workbaskets from the import - for (WorkbasketDefinitionRepresentationModel definition : definitions) { - Workbasket importedWb = workbasketDefinitionAssembler - .toEntityModel(definition.getWorkbasket()); + for (WorkbasketDefinitionRepresentationModel definition : definitions.getContent()) { + Workbasket importedWb = + workbasketDefinitionAssembler.toEntityModel(definition.getWorkbasket()); String newId; WorkbasketImpl wbWithoutId = (WorkbasketImpl) removeId(importedWb); if (systemIds.containsKey(logicalId(importedWb))) { @@ -160,8 +165,9 @@ public class WorkbasketDefinitionController { boolean authenticated = definition.getAuthorizations().stream() .anyMatch( - access -> (access.getWorkbasketId().equals(importedWb.getId())) - && (access.getWorkbasketKey().equals(importedWb.getKey()))); + access -> + (access.getWorkbasketId().equals(importedWb.getId())) + && (access.getWorkbasketKey().equals(importedWb.getKey()))); if (!authenticated && !definition.getAuthorizations().isEmpty()) { throw new InvalidWorkbasketException( "The given Authentications for Workbasket " @@ -181,7 +187,7 @@ public class WorkbasketDefinitionController { // STEP 2: update distribution targets // This can not be done in step 1 because the system IDs are only known after step 1 - for (WorkbasketDefinitionRepresentationModel definition : definitions) { + for (WorkbasketDefinitionRepresentationModel definition : definitions.getContent()) { List distributionTargets = new ArrayList<>(); for (String oldId : definition.getDistributionTargets()) { if (idConversion.containsKey(oldId)) { @@ -211,7 +217,7 @@ public class WorkbasketDefinitionController { return workbasketDefinitionAssembler.toEntityModel(wbRes); } - private void checkForDuplicates(List definitions) { + private void checkForDuplicates(Collection definitions) { List identifiers = new ArrayList<>(); Set duplicates = new HashSet<>(); for (WorkbasketDefinitionRepresentationModel definition : definitions) { diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/DistributionTargetRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/DistributionTargetRepresentationModelAssembler.java index d7100f05c..8b1378917 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/DistributionTargetRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/DistributionTargetRepresentationModelAssembler.java @@ -1,21 +1 @@ -package pro.taskana.workbasket.rest.assembler; -import static pro.taskana.common.rest.models.TaskanaPagedModelKeys.DISTRIBUTION_TARGETS; - -import org.springframework.stereotype.Component; - -import pro.taskana.common.rest.models.TaskanaPagedModelKeys; - -/** - * Transforms WorkbasketSummary to its resource counterpart DistributionTargerResource and vice - * versa. - */ -@Component -public class DistributionTargetRepresentationModelAssembler - extends WorkbasketSummaryRepresentationModelAssembler { - - @Override - protected TaskanaPagedModelKeys getKey() { - return DISTRIBUTION_TARGETS; - } -} diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketAccessItemRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketAccessItemRepresentationModelAssembler.java index c9f64bdd9..cb2751932 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketAccessItemRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketAccessItemRepresentationModelAssembler.java @@ -58,7 +58,7 @@ public class WorkbasketAccessItemRepresentationModelAssembler return wbAccItemModel; } - public TaskanaPagedModel toPageModel( + public TaskanaPagedModel toPageModelForSingleWorkbasket( String workbasketId, List workbasketAccessItems, PageMetadata pageMetadata) diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketDefinitionRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketDefinitionRepresentationModelAssembler.java index c8c85bf26..908016de7 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketDefinitionRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketDefinitionRepresentationModelAssembler.java @@ -1,6 +1,5 @@ package pro.taskana.workbasket.rest.assembler; -import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -11,6 +10,9 @@ import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; import pro.taskana.common.api.exceptions.NotAuthorizedException; +import pro.taskana.common.api.exceptions.SystemException; +import pro.taskana.common.rest.assembler.TaskanaPagingAssembler; +import pro.taskana.common.rest.models.TaskanaPagedModelKeys; import pro.taskana.workbasket.api.WorkbasketService; import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; import pro.taskana.workbasket.api.models.Workbasket; @@ -27,41 +29,40 @@ import pro.taskana.workbasket.rest.models.WorkbasketRepresentationModelWithoutLi * all additional information about that workbasket. */ @Component -public class WorkbasketDefinitionRepresentationModelAssembler { +public class WorkbasketDefinitionRepresentationModelAssembler + implements TaskanaPagingAssembler { private final WorkbasketService workbasketService; @Autowired - public WorkbasketDefinitionRepresentationModelAssembler( - WorkbasketService workbasketService) { + public WorkbasketDefinitionRepresentationModelAssembler(WorkbasketService workbasketService) { this.workbasketService = workbasketService; } - /** - * maps the distro targets to their id to remove overhead. - * - * @param workbasket {@link Workbasket} which will be converted - * @return a {@link WorkbasketDefinitionRepresentationModel}, containing the {@code basket}, its - * distribution targets and its authorizations - * @throws NotAuthorizedException if the user is not authorized - * @throws WorkbasketNotFoundException if {@code basket} is an unknown workbasket - */ @NonNull - public WorkbasketDefinitionRepresentationModel toModel(Workbasket workbasket) - throws NotAuthorizedException, WorkbasketNotFoundException { + public WorkbasketDefinitionRepresentationModel toModel(@NonNull Workbasket workbasket) { WorkbasketRepresentationModelWithoutLinks basket = new WorkbasketRepresentationModelWithoutLinks(workbasket); List authorizations = new ArrayList<>(); - for (WorkbasketAccessItem accessItem : - workbasketService.getWorkbasketAccessItems(basket.getWorkbasketId())) { - authorizations.add((WorkbasketAccessItemImpl) accessItem); + try { + for (WorkbasketAccessItem accessItem : + workbasketService.getWorkbasketAccessItems(basket.getWorkbasketId())) { + authorizations.add((WorkbasketAccessItemImpl) accessItem); + } + } catch (NotAuthorizedException e) { + throw new SystemException("Caught Exception", e); + } + Set distroTargets = null; + try { + distroTargets = + workbasketService.getDistributionTargets(workbasket.getId()).stream() + .map(WorkbasketSummary::getId) + .collect(Collectors.toSet()); + } catch (NotAuthorizedException | WorkbasketNotFoundException e) { + throw new SystemException("Caught Exception", e); } - Set distroTargets = - workbasketService.getDistributionTargets(workbasket.getId()).stream() - .map(WorkbasketSummary::getId) - .collect(Collectors.toSet()); return new WorkbasketDefinitionRepresentationModel(basket, distroTargets, authorizations); } @@ -72,12 +73,13 @@ public class WorkbasketDefinitionRepresentationModelAssembler { BeanUtils.copyProperties(wbResource, workbasket); workbasket.setId(wbResource.getWorkbasketId()); - if (wbResource.getModified() != null) { - workbasket.setModified(Instant.parse(wbResource.getModified())); - } - if (wbResource.getCreated() != null) { - workbasket.setCreated(Instant.parse(wbResource.getCreated())); - } + workbasket.setModified(wbResource.getModified()); + workbasket.setCreated(wbResource.getCreated()); return workbasket; } + + @Override + public TaskanaPagedModelKeys getProperty() { + return TaskanaPagedModelKeys.WORKBASKET_DEFINITIONS; + } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketRepresentationModelAssembler.java index 8dad7726a..f77497358 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketRepresentationModelAssembler.java @@ -3,7 +3,6 @@ package pro.taskana.workbasket.rest.assembler; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; -import java.time.Instant; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.server.RepresentationModelAssembler; @@ -32,8 +31,7 @@ public class WorkbasketRepresentationModelAssembler private final WorkbasketService workbasketService; @Autowired - public WorkbasketRepresentationModelAssembler( - WorkbasketService workbasketService) { + public WorkbasketRepresentationModelAssembler(WorkbasketService workbasketService) { this.workbasketService = workbasketService; } @@ -55,12 +53,8 @@ public class WorkbasketRepresentationModelAssembler BeanUtils.copyProperties(wbResource, workbasket); workbasket.setId(wbResource.getWorkbasketId()); - if (wbResource.getModified() != null) { - workbasket.setModified(Instant.parse(wbResource.getModified())); - } - if (wbResource.getCreated() != null) { - workbasket.setCreated(Instant.parse(wbResource.getCreated())); - } + workbasket.setModified(wbResource.getModified()); + workbasket.setCreated(wbResource.getCreated()); return workbasket; } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketSummaryRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketSummaryRepresentationModelAssembler.java index daea462fb..b656c5074 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketSummaryRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/assembler/WorkbasketSummaryRepresentationModelAssembler.java @@ -1,5 +1,6 @@ package pro.taskana.workbasket.rest.assembler; +import static pro.taskana.common.rest.models.TaskanaPagedModelKeys.DISTRIBUTION_TARGETS; import static pro.taskana.common.rest.models.TaskanaPagedModelKeys.WORKBASKETS; import java.util.List; @@ -13,7 +14,6 @@ import org.springframework.stereotype.Component; import pro.taskana.common.rest.Mapping; import pro.taskana.common.rest.models.TaskanaPagedModel; -import pro.taskana.common.rest.models.TaskanaPagedModelKeys; import pro.taskana.resource.rest.PageLinks; import pro.taskana.workbasket.api.WorkbasketService; import pro.taskana.workbasket.api.models.WorkbasketSummary; @@ -60,10 +60,17 @@ public class WorkbasketSummaryRepresentationModelAssembler implements .collect( Collectors.collectingAndThen( Collectors.toList(), - list -> new TaskanaPagedModel<>(getKey(), list, pageMetadata))); + list -> new TaskanaPagedModel<>(WORKBASKETS, list, pageMetadata))); } - protected TaskanaPagedModelKeys getKey() { - return WORKBASKETS; + @PageLinks(Mapping.URL_WORKBASKET_ID_DISTRIBUTION) + public TaskanaPagedModel toDistributionTargetPageModel( + List workbasketSummaries, PageMetadata pageMetadata) { + return workbasketSummaries.stream() + .map(this::toModel) + .collect( + Collectors.collectingAndThen( + Collectors.toList(), + list -> new TaskanaPagedModel<>(DISTRIBUTION_TARGETS, list, pageMetadata))); } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/models/WorkbasketRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/models/WorkbasketRepresentationModel.java index 0355805c9..eaffe2067 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/models/WorkbasketRepresentationModel.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/workbasket/rest/models/WorkbasketRepresentationModel.java @@ -1,5 +1,7 @@ package pro.taskana.workbasket.rest.models; +import java.time.Instant; + import pro.taskana.workbasket.api.models.Workbasket; /** @@ -9,49 +11,31 @@ public class WorkbasketRepresentationModel extends WorkbasketSummaryRepresentationModel { - private String created; // ISO-8601 - private String modified; // ISO-8601 + private Instant created; // ISO-8601 + private Instant modified; // ISO-8601 public WorkbasketRepresentationModel() { } public WorkbasketRepresentationModel(Workbasket workbasket) { super(workbasket); - this.created = workbasket.getCreated() != null ? workbasket.getCreated().toString() : null; - this.modified = workbasket.getModified() != null ? workbasket.getModified().toString() : null; + this.created = workbasket.getCreated(); + this.modified = workbasket.getModified(); } - public String getCreated() { + public Instant getCreated() { return created; } - public void setCreated(String created) { + public void setCreated(Instant created) { this.created = created; } - public String getModified() { + public Instant getModified() { return modified; } - public void setModified(String modified) { + public void setModified(Instant modified) { this.modified = modified; } - - @Override - public String toString() { - return "WorkbasketResource [" - + "workbasketId= " - + this.workbasketId - + "key= " - + this.key - + "name= " - + this.name - + "domain= " - + this.domain - + "type= " - + this.type - + "owner= " - + this.owner - + "]"; - } } diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationControllerIntTest.java index 97fcec6c0..337e3368d 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationControllerIntTest.java @@ -103,18 +103,19 @@ class ClassificationControllerIntTest { ResponseEntity> response = template.exchange( restHelper.toUrl(Mapping.URL_CLASSIFICATIONS) - + "?domain=DOMAIN_A&sort-by=key&order=asc&page=2&page-size=5", + + "?domain=DOMAIN_A&sort-by=key&order=asc&page-size=5&page=2", HttpMethod.GET, restHelper.defaultRequest(), CLASSIFICATION_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody().getContent()).hasSize(5); assertThat(response.getBody().getContent().iterator().next().getKey()).isEqualTo("L1050"); assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); + String href = response + .getBody() + .getRequiredLink(IanaLinkRelations.SELF) + .getHref(); assertThat( - response - .getBody() - .getRequiredLink(IanaLinkRelations.SELF) - .getHref() + href .endsWith( "/api/v1/classifications?" + "domain=DOMAIN_A&sort-by=key&order=asc&page-size=5&page=2")) diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationDefinitionControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationDefinitionControllerIntTest.java index 0ddb4ee9f..2eeb14cae 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationDefinitionControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationDefinitionControllerIntTest.java @@ -9,8 +9,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -27,28 +28,47 @@ import org.springframework.http.ResponseEntity; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.RestTemplate; +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; +import pro.taskana.classification.rest.assembler.ClassificationRepresentationModelAssembler; import pro.taskana.classification.rest.models.ClassificationRepresentationModel; import pro.taskana.classification.rest.models.ClassificationSummaryRepresentationModel; import pro.taskana.common.rest.Mapping; import pro.taskana.common.rest.RestHelper; import pro.taskana.common.rest.TaskanaSpringBootTest; import pro.taskana.common.rest.models.TaskanaPagedModel; +import pro.taskana.common.rest.models.TaskanaPagedModelKeys; /** Test classification definitions. */ @TaskanaSpringBootTest class ClassificationDefinitionControllerIntTest { private static final ParameterizedTypeReference< - TaskanaPagedModel> - CLASSIFICATION_SUMMARY_PAGE_MODEL_TYPE = - new ParameterizedTypeReference< - TaskanaPagedModel>() {}; + TaskanaPagedModel> + CLASSIFICATION_PAGE_MODEL_TYPE = + new ParameterizedTypeReference>() {}; private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationController.class); private static RestTemplate template; - @Autowired RestHelper restHelper; - private ObjectMapper objMapper = new ObjectMapper(); + + private final RestHelper restHelper; + private final ObjectMapper mapper; + private final ClassificationService classificationService; + private final ClassificationRepresentationModelAssembler classificationAssembler; + + @Autowired + ClassificationDefinitionControllerIntTest( + RestHelper restHelper, + ObjectMapper mapper, + ClassificationService classificationService, + ClassificationRepresentationModelAssembler classificationAssembler) { + this.restHelper = restHelper; + this.mapper = mapper; + this.classificationService = classificationService; + this.classificationAssembler = classificationAssembler; + } @BeforeAll static void init() { @@ -57,27 +77,34 @@ class ClassificationDefinitionControllerIntTest { @Test void testExportClassifications() { - ResponseEntity response = + ResponseEntity> response = template.exchange( restHelper.toUrl(Mapping.URL_CLASSIFICATIONDEFINITION) + "?domain=DOMAIN_B", HttpMethod.GET, restHelper.defaultRequest(), - ParameterizedTypeReference.forType(ClassificationRepresentationModel[].class)); + CLASSIFICATION_PAGE_MODEL_TYPE); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody().length >= 5).isTrue(); - assertThat(response.getBody().length <= 7).isTrue(); - assertThat(response.getBody()[0]).isInstanceOf(ClassificationRepresentationModel.class); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getContent()) + .extracting(ClassificationRepresentationModel::getClassificationId) + .containsOnlyOnce( + "CLI:200000000000000000000000000000000015", + "CLI:200000000000000000000000000000000017", + "CLI:200000000000000000000000000000000018", + "CLI:200000000000000000000000000000000003", + "CLI:200000000000000000000000000000000004"); } @Test void testExportClassificationsFromWrongDomain() { - ResponseEntity response = + ResponseEntity> response = template.exchange( restHelper.toUrl(Mapping.URL_CLASSIFICATIONDEFINITION) + "?domain=ADdfe", HttpMethod.GET, restHelper.defaultRequest(), - ParameterizedTypeReference.forType(ClassificationRepresentationModel[].class)); - assertThat(response.getBody()).isEmpty(); + CLASSIFICATION_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getContent()).isEmpty(); } @Test @@ -91,8 +118,8 @@ class ClassificationDefinitionControllerIntTest { classification.setType("TASK"); classification.setDomain("DOMAIN_A"); classification.setIsValidInDomain(true); - classification.setCreated("2016-05-12T10:12:12.12Z"); - classification.setModified("2018-05-12T10:12:12.12Z"); + classification.setCreated(Instant.parse("2016-05-12T10:12:12.12Z")); + classification.setModified(Instant.parse("2018-05-12T10:12:12.12Z")); classification.setName("name"); classification.setDescription("description"); classification.setPriority(4); @@ -107,8 +134,9 @@ class ClassificationDefinitionControllerIntTest { classification.setCustom7("custom"); classification.setCustom8("custom"); - List clList = new ArrayList<>(); - clList.add(objMapper.writeValueAsString(classification)); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Collections.singletonList(classification)); ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); @@ -118,8 +146,9 @@ class ClassificationDefinitionControllerIntTest { void testFailureWhenKeyIsMissing() throws IOException { ClassificationRepresentationModel classification = new ClassificationRepresentationModel(); classification.setDomain("DOMAIN_A"); - List clList = new ArrayList<>(); - clList.add(objMapper.writeValueAsString(classification)); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Collections.singletonList(classification)); try { importRequest(clList); @@ -132,8 +161,9 @@ class ClassificationDefinitionControllerIntTest { void testFailureWhenDomainIsMissing() throws IOException { ClassificationRepresentationModel classification = new ClassificationRepresentationModel(); classification.setKey("one"); - List clList = new ArrayList<>(); - clList.add(objMapper.writeValueAsString(classification)); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Collections.singletonList(classification)); try { importRequest(clList); @@ -143,25 +173,25 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testFailureWhenUpdatingTypeOfExistingClassification() throws IOException { - ClassificationSummaryRepresentationModel classification = - this.getClassificationWithKeyAndDomain("T6310", ""); + void testFailureWhenUpdatingTypeOfExistingClassification() throws Exception { + ClassificationRepresentationModel classification = + getClassificationWithKeyAndDomain("T6310", ""); classification.setType("DOCUMENT"); - List clList = new ArrayList<>(); - clList.add(objMapper.writeValueAsString(classification)); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Collections.singletonList(classification)); - try { - importRequest(clList); - } catch (HttpClientErrorException e) { - assertThat(e.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); - } + assertThatThrownBy(() -> importRequest(clList)) + .isInstanceOf(HttpClientErrorException.class) + .extracting(e -> (HttpClientErrorException) e) + .extracting(HttpClientErrorException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); } @Test void testImportMultipleClassifications() throws IOException { ClassificationRepresentationModel classification1 = this.createClassification("id1", "ImportKey1", "DOMAIN_A", null, null); - final String c1 = objMapper.writeValueAsString(classification1); ClassificationRepresentationModel classification2 = this.createClassification( @@ -169,77 +199,81 @@ class ClassificationDefinitionControllerIntTest { classification2.setCategory("MANUAL"); classification2.setType("TASK"); classification2.setIsValidInDomain(true); - classification2.setCreated("2016-05-12T10:12:12.12Z"); - classification2.setModified("2018-05-12T10:12:12.12Z"); + classification2.setCreated(Instant.parse("2016-05-12T10:12:12.12Z")); + classification2.setModified(Instant.parse("2018-05-12T10:12:12.12Z")); classification2.setName("name"); classification2.setDescription("description"); classification2.setPriority(4); classification2.setServiceLevel("P2D"); classification2.setApplicationEntryPoint("entry1"); - String c2 = objMapper.writeValueAsString(classification2); - List clList = new ArrayList<>(); - clList.add(c1); - clList.add(c2); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Arrays.asList(classification1, classification2)); ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); } @Test - void testImportDuplicateClassification() throws IOException { + void testImportDuplicateClassification() { ClassificationRepresentationModel classification1 = new ClassificationRepresentationModel(); classification1.setClassificationId("id1"); classification1.setKey("ImportKey3"); classification1.setDomain("DOMAIN_A"); - String c1 = objMapper.writeValueAsString(classification1); - List clList = new ArrayList<>(); - clList.add(c1); - clList.add(c1); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Arrays.asList(classification1, classification1)); - try { - importRequest(clList); - } catch (HttpClientErrorException e) { - assertThat(e.getStatusCode()).isEqualTo(HttpStatus.CONFLICT); - } + assertThatThrownBy(() -> importRequest(clList)) + .isInstanceOf(HttpClientErrorException.class) + .extracting(e -> (HttpClientErrorException) e) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.CONFLICT); } @Test - void testInsertExistingClassificationWithOlderTimestamp() throws IOException { - ClassificationSummaryRepresentationModel existingClassification = + void testInsertExistingClassificationWithOlderTimestamp() throws Exception { + ClassificationRepresentationModel existingClassification = getClassificationWithKeyAndDomain("L110107", "DOMAIN_A"); existingClassification.setName("first new Name"); - List clList = new ArrayList<>(); - clList.add(objMapper.writeValueAsString(existingClassification)); + + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, + Collections.singletonList(existingClassification)); ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); existingClassification.setName("second new Name"); - clList = new ArrayList<>(); - clList.add(objMapper.writeValueAsString(existingClassification)); + clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, + Collections.singletonList(existingClassification)); response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - ClassificationSummaryRepresentationModel testClassification = + ClassificationRepresentationModel testClassification = this.getClassificationWithKeyAndDomain("L110107", "DOMAIN_A"); assertThat(testClassification.getName()).isEqualTo("second new Name"); } @Test - void testHookExistingChildToNewParent() throws IOException { + void testHookExistingChildToNewParent() throws Exception { final ClassificationRepresentationModel newClassification = createClassification("new Classification", "newClass", "DOMAIN_A", null, "L11010"); - ClassificationSummaryRepresentationModel existingClassification = + ClassificationRepresentationModel existingClassification = getClassificationWithKeyAndDomain("L110102", "DOMAIN_A"); existingClassification.setParentId("new Classification"); existingClassification.setParentKey("newClass"); - List clList = new ArrayList<>(); - clList.add(objMapper.writeValueAsString(existingClassification)); - clList.add(objMapper.writeValueAsString(newClassification)); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, + Arrays.asList(existingClassification, newClassification)); ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); @@ -259,41 +293,37 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testImportParentAndChildClassification() throws IOException { + void testImportParentAndChildClassification() throws Exception { ClassificationRepresentationModel classification1 = this.createClassification("parentId", "ImportKey6", "DOMAIN_A", null, null); - final String c1 = objMapper.writeValueAsString(classification1); - ClassificationRepresentationModel classification2 = this.createClassification("childId1", "ImportKey7", "DOMAIN_A", null, "ImportKey6"); - final String c21 = objMapper.writeValueAsString(classification2); - classification2 = - this.createClassification("childId2", "ImportKey8", "DOMAIN_A", "parentId", null); - final String c22 = objMapper.writeValueAsString(classification2); - ClassificationRepresentationModel classification3 = + this.createClassification("childId2", "ImportKey8", "DOMAIN_A", "parentId", null); + ClassificationRepresentationModel classification4 = this.createClassification( "grandchildId1", "ImportKey9", "DOMAIN_A", "childId1", "ImportKey7"); - final String c31 = objMapper.writeValueAsString(classification3); - classification3 = + ClassificationRepresentationModel classification5 = this.createClassification("grandchild2", "ImportKey10", "DOMAIN_A", null, "ImportKey7"); - final String c32 = objMapper.writeValueAsString(classification3); - List clList = new ArrayList<>(); - clList.add(c31); - clList.add(c32); - clList.add(c21); - clList.add(c22); - clList.add(c1); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, + Arrays.asList( + classification1, + classification2, + classification3, + classification4, + classification5)); ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - ClassificationSummaryRepresentationModel parentCl = + ClassificationRepresentationModel parentCl = getClassificationWithKeyAndDomain("ImportKey6", "DOMAIN_A"); - ClassificationSummaryRepresentationModel childCl = + ClassificationRepresentationModel childCl = getClassificationWithKeyAndDomain("ImportKey7", "DOMAIN_A"); - ClassificationSummaryRepresentationModel grandchildCl = + ClassificationRepresentationModel grandchildCl = getClassificationWithKeyAndDomain("ImportKey9", "DOMAIN_A"); assertThat(parentCl).isNotNull(); @@ -304,31 +334,27 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testImportParentAndChildClassificationWithKey() throws IOException { - ClassificationRepresentationModel classification1 = + void testImportParentAndChildClassificationWithKey() throws Exception { + ClassificationRepresentationModel parent = createClassification("parent", "ImportKey11", "DOMAIN_A", null, null); - classification1.setCustom1("parent is correct"); - String parent = objMapper.writeValueAsString(classification1); - ClassificationRepresentationModel classification2 = + parent.setCustom1("parent is correct"); + ClassificationRepresentationModel wrongParent = createClassification("wrongParent", "ImportKey11", "DOMAIN_B", null, null); - String wrongParent = objMapper.writeValueAsString(classification2); - ClassificationRepresentationModel classification3 = + ClassificationRepresentationModel child = createClassification("child", "ImportKey13", "DOMAIN_A", null, "ImportKey11"); - String child = objMapper.writeValueAsString(classification3); - List clList = new ArrayList<>(); - clList.add(wrongParent); - clList.add(parent); - clList.add(child); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Arrays.asList(parent, wrongParent, child)); ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - ClassificationSummaryRepresentationModel rightParentCl = + ClassificationRepresentationModel rightParentCl = getClassificationWithKeyAndDomain("ImportKey11", "DOMAIN_A"); - ClassificationSummaryRepresentationModel wrongParentCl = + ClassificationRepresentationModel wrongParentCl = getClassificationWithKeyAndDomain("ImportKey11", "DOMAIN_B"); - ClassificationSummaryRepresentationModel childCl = + ClassificationRepresentationModel childCl = getClassificationWithKeyAndDomain("ImportKey13", "DOMAIN_A"); assertThat(rightParentCl).isNotNull(); @@ -339,50 +365,46 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testChangeParentByImportingExistingClassification() - throws IOException, InterruptedException { - ClassificationSummaryRepresentationModel child1 = + void testChangeParentByImportingExistingClassification() throws Exception { + ClassificationRepresentationModel child1 = this.getClassificationWithKeyAndDomain("L110105", "DOMAIN_A"); assertThat(child1.getParentKey()).isEqualTo("L11010"); child1.setParentId("CLI:100000000000000000000000000000000002"); child1.setParentKey("L10303"); - final String withNewParent = objMapper.writeValueAsString(child1); - ClassificationSummaryRepresentationModel child2 = + ClassificationRepresentationModel child2 = this.getClassificationWithKeyAndDomain("L110107", "DOMAIN_A"); assertThat(child2.getParentKey()).isEqualTo("L11010"); child2.setParentId(""); child2.setParentKey(""); - String withoutParent = objMapper.writeValueAsString(child2); - List clList = new ArrayList<>(); - clList.add(withNewParent); - clList.add(withoutParent); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Arrays.asList(child1, child2)); ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); Thread.sleep(10); LOGGER.debug("Wait 10 ms to give the system a chance to update"); - ClassificationSummaryRepresentationModel childWithNewParent = + ClassificationRepresentationModel childWithNewParent = this.getClassificationWithKeyAndDomain("L110105", "DOMAIN_A"); assertThat(childWithNewParent.getParentKey()).isEqualTo(child1.getParentKey()); - ClassificationSummaryRepresentationModel childWithoutParent = + ClassificationRepresentationModel childWithoutParent = this.getClassificationWithKeyAndDomain("L110107", "DOMAIN_A"); assertThat(childWithoutParent.getParentId()).isEqualTo(child2.getParentId()); assertThat(childWithoutParent.getParentKey()).isEqualTo(child2.getParentKey()); } @Test - void testFailOnImportDuplicates() throws IOException { - ClassificationSummaryRepresentationModel classification = + void testFailOnImportDuplicates() throws Exception { + ClassificationRepresentationModel classification = this.getClassificationWithKeyAndDomain("L110105", "DOMAIN_A"); - String classificationString = objMapper.writeValueAsString(classification); - List clList = new ArrayList<>(); - clList.add(classificationString); - clList.add(classificationString); + TaskanaPagedModel clList = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.CLASSIFICATIONS, Arrays.asList(classification, classification)); assertThatThrownBy(() -> importRequest(clList)) .isInstanceOf(HttpClientErrorException.class) @@ -402,29 +424,18 @@ class ClassificationDefinitionControllerIntTest { return classificationRepresentationModel; } - private ClassificationSummaryRepresentationModel getClassificationWithKeyAndDomain( - String key, String domain) { - LOGGER.debug("Request classification with key={} in domain={}", key, domain); - HttpEntity request = new HttpEntity<>(restHelper.getHeaders()); - ResponseEntity> response = - template.exchange( - restHelper.toUrl(Mapping.URL_CLASSIFICATIONS) + "?key=" + key + "&domain=" + domain, - HttpMethod.GET, - request, - CLASSIFICATION_SUMMARY_PAGE_MODEL_TYPE); - return response - .getBody() - .getContent() - .toArray(new ClassificationSummaryRepresentationModel[1])[0]; + private ClassificationRepresentationModel getClassificationWithKeyAndDomain( + String key, String domain) throws ClassificationNotFoundException { + return classificationAssembler.toModel(classificationService.getClassification(key, domain)); } - private ResponseEntity importRequest(List clList) throws IOException { + private ResponseEntity importRequest( + TaskanaPagedModel clList) throws IOException { LOGGER.debug("Start Import"); File tmpFile = File.createTempFile("test", ".tmp"); OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tmpFile), StandardCharsets.UTF_8); - writer.write(clList.toString()); - writer.close(); + mapper.writeValue(writer, clList); MultiValueMap body = new LinkedMultiValueMap<>(); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/RestHelper.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/RestHelper.java index 3d8ad5f85..152748be8 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/RestHelper.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/RestHelper.java @@ -3,12 +3,16 @@ package pro.taskana.common.rest; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; +import java.util.Collections; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; +import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.mediatype.hal.Jackson2HalModule; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @@ -81,9 +85,11 @@ public class RestHelper { mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); mapper.registerModule(new Jackson2HalModule()); - + mapper.registerModule(new ParameterNamesModule()) + .registerModule(new Jdk8Module()) + .registerModule(new JavaTimeModule()); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); - converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json")); + converter.setSupportedMediaTypes(Collections.singletonList(MediaTypes.HAL_JSON)); converter.setObjectMapper(mapper); RestTemplate template = new RestTemplate(); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/ClassificationDefinitionControllerRestDocumentation.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/ClassificationDefinitionControllerRestDocumentation.java index c4640e17f..2471bccdb 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/ClassificationDefinitionControllerRestDocumentation.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/ClassificationDefinitionControllerRestDocumentation.java @@ -27,8 +27,8 @@ class ClassificationDefinitionControllerRestDocumentation extends BaseRestDocume classificationDefinitionsFieldDescriptors = new FieldDescriptor[] { - subsectionWithPath("[]") - .description("An array of <>") + subsectionWithPath("classifications") + .description("An array of <>") }; } @@ -49,7 +49,8 @@ class ClassificationDefinitionControllerRestDocumentation extends BaseRestDocume @Test void importClassificationDefinitions() throws Exception { - String definitionString = "[{\"key\":\"Key0815\", \"domain\":\"DOMAIN_B\"}]"; + String definitionString = + "{\"classifications\":[{\"key\":\"Key0815\", \"domain\":\"DOMAIN_B\"}]}"; this.mockMvc .perform( diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/WorkbasketControllerRestDocumentation.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/WorkbasketControllerRestDocumentation.java index 1792f03d1..8e001c790 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/WorkbasketControllerRestDocumentation.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/WorkbasketControllerRestDocumentation.java @@ -406,9 +406,9 @@ class WorkbasketControllerRestDocumentation extends BaseRestDocumentation { this.mockMvc .perform( RestDocumentationRequestBuilders.get( - restHelper.toUrl( - Mapping.URL_WORKBASKET_ID_DISTRIBUTION, - "WBI:100000000000000000000000000000000002")) + restHelper.toUrl( + Mapping.URL_WORKBASKET_ID_DISTRIBUTION, + "WBI:100000000000000000000000000000000002")) .header("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x")) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo( diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/WorkbasketDefinitionControllerRestDocumentation.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/WorkbasketDefinitionControllerRestDocumentation.java index 6b9e201d5..7296ac820 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/WorkbasketDefinitionControllerRestDocumentation.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/doc/api/WorkbasketDefinitionControllerRestDocumentation.java @@ -27,8 +27,10 @@ class WorkbasketDefinitionControllerRestDocumentation extends BaseRestDocumentat workbasketDefinitionsFieldDescriptors = new FieldDescriptor[] { - subsectionWithPath("[]") - .description("An array of <>") + subsectionWithPath("workbasketDefinitions") + .description( + "An array of <>") }; } @@ -49,7 +51,7 @@ class WorkbasketDefinitionControllerRestDocumentation extends BaseRestDocumentat @Test void importWorkbasketDefinition() throws Exception { String definitionString = - "[" + "{ \"workbasketDefinitions\": [" + "{" + "\"distributionTargets\":[], " + "\"authorizations\":[], " @@ -57,7 +59,7 @@ class WorkbasketDefinitionControllerRestDocumentation extends BaseRestDocumentat + "\"domain\": \"DOMAIN_A\", \"type\":\"GROUP\" , " + "\"workbasketId\":\"gibtsNed\"}" + "}" - + "]"; + + "]}"; this.mockMvc .perform( diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java index 36cc4f245..ebcfbd745 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java @@ -3,8 +3,8 @@ package pro.taskana.task.rest; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static pro.taskana.common.rest.RestHelper.TEMPLATE; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.BufferedReader; @@ -18,7 +18,6 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import javax.sql.DataSource; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -30,7 +29,6 @@ import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; import pro.taskana.classification.rest.models.ClassificationSummaryRepresentationModel; import pro.taskana.common.rest.Mapping; @@ -51,18 +49,18 @@ class TaskControllerIntTest { private static final ParameterizedTypeReference> TASK_SUMMARY_PAGE_MODEL_TYPE = new ParameterizedTypeReference>() {}; - private static RestTemplate template; + private final RestHelper restHelper; + private final ObjectMapper mapper; + private final DataSource dataSource; @Value("${taskana.schemaName:TASKANA}") public String schemaName; - @Autowired RestHelper restHelper; - - @Autowired private DataSource dataSource; - - @BeforeAll - static void init() { - template = RestHelper.TEMPLATE; + @Autowired + TaskControllerIntTest(RestHelper restHelper, ObjectMapper mapper, DataSource dataSource) { + this.restHelper = restHelper; + this.mapper = mapper; + this.dataSource = dataSource; } void resetDb() { @@ -73,29 +71,27 @@ class TaskControllerIntTest { @Test void testGetAllTasks() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS), HttpMethod.GET, restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(25); } @Test void testGetAllTasksByWorkbasketId() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-id=WBI:100000000000000000000000000000000001", HttpMethod.GET, restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(22); } @@ -108,7 +104,7 @@ class TaskControllerIntTest { Instant fourthInstant = Instant.now().minus(11, ChronoUnit.DAYS); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-id=WBI:100000000000000000000000000000000001" + "&planned=" @@ -125,8 +121,7 @@ class TaskControllerIntTest { restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(6); } @@ -137,7 +132,7 @@ class TaskControllerIntTest { Instant plannedToInstant = Instant.now().minus(3, ChronoUnit.DAYS); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-id=WBI:100000000000000000000000000000000001" + "&planned-from=" @@ -149,8 +144,7 @@ class TaskControllerIntTest { restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(3); } @@ -160,7 +154,7 @@ class TaskControllerIntTest { Instant plannedFromInstant = Instant.now().minus(6, ChronoUnit.DAYS); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-id=WBI:100000000000000000000000000000000001" + "&planned-from=" @@ -170,25 +164,25 @@ class TaskControllerIntTest { restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(4); } @Test void testGetAllTasksByWorkbasketIdWithInvalidPlannedParamsCombination() { ThrowingCallable httpCall = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&planned=2020-01-22T09:44:47.453Z,," - + "2020-01-19T07:44:47.453Z,2020-01-19T19:44:47.453Z," - + ",2020-01-18T09:44:47.453Z" - + "&planned-from=2020-01-19T07:44:47.453Z" - + "&sort-by=planned", - HttpMethod.GET, - restHelper.defaultRequest(), - TASK_SUMMARY_PAGE_MODEL_TYPE); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&planned=2020-01-22T09:44:47.453Z,," + + "2020-01-19T07:44:47.453Z,2020-01-19T19:44:47.453Z," + + ",2020-01-18T09:44:47.453Z" + + "&planned-from=2020-01-19T07:44:47.453Z" + + "&sort-by=planned", + HttpMethod.GET, + restHelper.defaultRequest(), + TASK_SUMMARY_PAGE_MODEL_TYPE); assertThatThrownBy(httpCall) .isInstanceOf(HttpClientErrorException.class) .hasMessageContaining("400"); @@ -203,7 +197,7 @@ class TaskControllerIntTest { Instant fourthInstant = Instant.now().minus(11, ChronoUnit.DAYS); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-id=WBI:100000000000000000000000000000000001" + "&due=" @@ -220,15 +214,14 @@ class TaskControllerIntTest { restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(6); } @Test void should_ReturnAllTasksByWildcardSearch_For_ProvidedSearchValue() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?wildcard-search-value=%99%" + "&wildcard-search-fields=NAME,custom_3,CuStOM_4", @@ -236,8 +229,7 @@ class TaskControllerIntTest { new HttpEntity(restHelper.getHeadersAdmin()), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(4); } @@ -245,11 +237,12 @@ class TaskControllerIntTest { void should_ThrowException_When_ProvidingInvalidWildcardSearchParameters() { ThrowingCallable httpCall = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_TASKS) + "?wildcard-search-value=%rt%", - HttpMethod.GET, - restHelper.defaultRequest(), - TASK_SUMMARY_PAGE_MODEL_TYPE); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_TASKS) + "?wildcard-search-value=%rt%", + HttpMethod.GET, + restHelper.defaultRequest(), + TASK_SUMMARY_PAGE_MODEL_TYPE); assertThatThrownBy(httpCall) .isInstanceOf(HttpClientErrorException.class) .hasMessageContaining("400") @@ -257,12 +250,13 @@ class TaskControllerIntTest { .isEqualTo(HttpStatus.BAD_REQUEST); ThrowingCallable httpCall2 = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_TASKS) - + "?wildcard-search-fields=NAME,CUSTOM_3,CUSTOM_4", - HttpMethod.GET, - restHelper.defaultRequest(), - TASK_SUMMARY_PAGE_MODEL_TYPE); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_TASKS) + + "?wildcard-search-fields=NAME,CUSTOM_3,CUSTOM_4", + HttpMethod.GET, + restHelper.defaultRequest(), + TASK_SUMMARY_PAGE_MODEL_TYPE); assertThatThrownBy(httpCall2) .isInstanceOf(HttpClientErrorException.class) .hasMessageContaining("400") @@ -277,7 +271,7 @@ class TaskControllerIntTest { Instant dueToInstant = Instant.now().minus(3, ChronoUnit.DAYS); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-id=WBI:100000000000000000000000000000000001" + "&due-from=" @@ -289,8 +283,7 @@ class TaskControllerIntTest { restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(9); } @@ -300,7 +293,7 @@ class TaskControllerIntTest { Instant dueToInstant = Instant.now().minus(1, ChronoUnit.DAYS); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-id=WBI:100000000000000000000000000000000001" + "&due-until=" @@ -310,25 +303,25 @@ class TaskControllerIntTest { restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(6); } @Test void testGetAllTasksByWorkbasketIdWithInvalidDueParamsCombination() { ThrowingCallable httpCall = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&due=2020-01-22T09:44:47.453Z,," - + "2020-01-19T07:44:47.453Z,2020-01-19T19:44:47.453Z," - + ",2020-01-18T09:44:47.453Z" - + "&due-from=2020-01-19T07:44:47.453Z" - + "&sort-by=planned", - HttpMethod.GET, - restHelper.defaultRequest(), - TASK_SUMMARY_PAGE_MODEL_TYPE); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&due=2020-01-22T09:44:47.453Z,," + + "2020-01-19T07:44:47.453Z,2020-01-19T19:44:47.453Z," + + ",2020-01-18T09:44:47.453Z" + + "&due-from=2020-01-19T07:44:47.453Z" + + "&sort-by=planned", + HttpMethod.GET, + restHelper.defaultRequest(), + TASK_SUMMARY_PAGE_MODEL_TYPE); assertThatThrownBy(httpCall) .isInstanceOf(HttpClientErrorException.class) .hasMessageContaining("400"); @@ -340,21 +333,20 @@ class TaskControllerIntTest { headers.add("Authorization", "Basic dXNlcl8xXzI6dXNlcl8xXzI="); // user_1_2 HttpEntity request = new HttpEntity<>(headers); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-key=USER_1_2&domain=DOMAIN_A", HttpMethod.GET, request, TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(20); } @Test void testGetAllTasksByExternalId() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?external-id=ETI:000000000000000000000000000000000003," + "ETI:000000000000000000000000000000000004", @@ -362,8 +354,7 @@ class TaskControllerIntTest { restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(2); } @@ -375,11 +366,12 @@ class TaskControllerIntTest { HttpEntity request = new HttpEntity<>(headers); ThrowingCallable httpCall = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-key=USER_1_2", - HttpMethod.GET, - request, - TASK_SUMMARY_PAGE_MODEL_TYPE); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_TASKS) + "?workbasket-key=USER_1_2", + HttpMethod.GET, + request, + TASK_SUMMARY_PAGE_MODEL_TYPE); assertThatThrownBy(httpCall) .isInstanceOf(HttpClientErrorException.class) .hasMessageContaining("400"); @@ -388,47 +380,46 @@ class TaskControllerIntTest { @Test void testGetAllTasksWithAdminRole() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS), HttpMethod.GET, new HttpEntity<>(restHelper.getHeadersAdmin()), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(73); } @Test void testGetAllTasksKeepingFilters() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?por.type=VNR&por.value=22334455&sort-by=por.value&order=desc", HttpMethod.GET, restHelper.defaultRequest(), TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)) - .isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat( - response - .getBody() - .getRequiredLink(IanaLinkRelations.SELF) - .getHref() - .endsWith( - "/api/v1/tasks?por.type=VNR&por.value=22334455&sort-by=por.value&order=desc")) + response + .getBody() + .getRequiredLink(IanaLinkRelations.SELF) + .getHref() + .endsWith( + "/api/v1/tasks?por.type=VNR&por.value=22334455&sort-by=por.value&order=desc")) .isTrue(); } @Test void testThrowsExceptionIfInvalidFilterIsUsed() { ThrowingCallable httpCall = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_TASKS) + "?invalid=VNR", - HttpMethod.GET, - restHelper.defaultRequest(), - TASK_SUMMARY_PAGE_MODEL_TYPE); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_TASKS) + "?invalid=VNR", + HttpMethod.GET, + restHelper.defaultRequest(), + TASK_SUMMARY_PAGE_MODEL_TYPE); assertThatThrownBy(httpCall) .isInstanceOf(HttpClientErrorException.class) .hasMessageContaining("[invalid]") @@ -441,7 +432,7 @@ class TaskControllerIntTest { HttpEntity request = new HttpEntity<>(restHelper.getHeadersAdmin()); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?state=READY,CLAIMED&sort-by=por.value&order=desc&page-size=5&page=14", HttpMethod.GET, @@ -450,11 +441,11 @@ class TaskControllerIntTest { assertThat(response.getBody()).isNotNull(); assertThat((response.getBody()).getContent()).hasSize(1); assertThat( - response - .getBody() - .getRequiredLink(IanaLinkRelations.LAST) - .getHref() - .contains("page=14")) + response + .getBody() + .getRequiredLink(IanaLinkRelations.LAST) + .getHref() + .contains("page=14")) .isTrue(); assertThat("TKI:100000000000000000000000000000000000") .isEqualTo(response.getBody().getContent().iterator().next().getTaskId()); @@ -487,7 +478,7 @@ class TaskControllerIntTest { HttpEntity request = new HttpEntity<>(headers); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?sort-by=due&order=desc", HttpMethod.GET, request, @@ -496,7 +487,7 @@ class TaskControllerIntTest { assertThat((response.getBody()).getContent()).hasSize(25); response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?sort-by=due&order=desc&page-size=5&page=5", HttpMethod.GET, request, @@ -504,18 +495,18 @@ class TaskControllerIntTest { assertThat(response.getBody()).isNotNull(); assertThat((response.getBody()).getContent()).hasSize(5); assertThat( - response.getBody().getRequiredLink(IanaLinkRelations.LAST).getHref().contains("page=5")) + response.getBody().getRequiredLink(IanaLinkRelations.LAST).getHref().contains("page=5")) .isTrue(); assertThat("TKI:000000000000000000000000000000000023") .isEqualTo(response.getBody().getContent().iterator().next().getTaskId()); assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat( - response - .getBody() - .getRequiredLink(IanaLinkRelations.SELF) - .getHref() - .endsWith("/api/v1/tasks?sort-by=due&order=desc&page-size=5&page=5")) + response + .getBody() + .getRequiredLink(IanaLinkRelations.SELF) + .getHref() + .endsWith("/api/v1/tasks?sort-by=due&order=desc&page-size=5&page=5")) .isTrue(); assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); @@ -533,7 +524,7 @@ class TaskControllerIntTest { headers.add("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"); HttpEntity request = new HttpEntity<>(headers); ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS) + "?por.company=00&por.system=PASystem&por.instance=00&" + "por.type=VNR&por.value=22334455&sort-by=por.type&" @@ -549,14 +540,14 @@ class TaskControllerIntTest { assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat( - response - .getBody() - .getRequiredLink(IanaLinkRelations.SELF) - .getHref() - .endsWith( - "/api/v1/tasks?por.company=00&por.system=PASystem&por.instance=00&" - + "por.type=VNR&por.value=22334455&sort-by=por.type&order=asc&" - + "page-size=5&page=2")) + response + .getBody() + .getRequiredLink(IanaLinkRelations.SELF) + .getHref() + .endsWith( + "/api/v1/tasks?por.company=00&por.system=PASystem&por.instance=00&" + + "por.type=VNR&por.value=22334455&sort-by=por.type&order=asc&" + + "page-size=5&page=2")) .isTrue(); assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); @@ -572,7 +563,6 @@ class TaskControllerIntTest { con.setRequestMethod("GET"); con.setRequestProperty("Authorization", "Basic YWRtaW46YWRtaW4="); assertThat(con.getResponseCode()).isEqualTo(200); - final ObjectMapper objectMapper = new ObjectMapper(); BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), UTF_8)); String inputLine; @@ -583,7 +573,7 @@ class TaskControllerIntTest { in.close(); con.disconnect(); String response = content.toString(); - JsonNode jsonNode = objectMapper.readTree(response); + JsonNode jsonNode = mapper.readTree(response); String created = jsonNode.get("created").asText(); assertThat(response.contains("\"attachments\":[]")).isFalse(); assertThat(created.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z")).isTrue(); @@ -634,8 +624,6 @@ class TaskControllerIntTest { in.close(); con.disconnect(); String updatedTask = content.toString(); - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); TaskRepresentationModel originalTaskObject = mapper.readValue(originalTask, TaskRepresentationModel.class); TaskRepresentationModel updatedTaskObject = @@ -649,7 +637,7 @@ class TaskControllerIntTest { TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); ResponseEntity responseCreate = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS), HttpMethod.POST, new HttpEntity<>(taskRepresentationModel, restHelper.getHeaders()), @@ -663,7 +651,7 @@ class TaskControllerIntTest { assertThat(taskIdOfCreatedTask.startsWith("TKI:")).isTrue(); ResponseEntity responseDeleted = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS_ID, taskIdOfCreatedTask), HttpMethod.DELETE, new HttpEntity<>(restHelper.getHeadersAdmin()), @@ -680,15 +668,16 @@ class TaskControllerIntTest { void testCreateWithPlannedAndDueDate() { TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); Instant now = Instant.now(); - taskRepresentationModel.setPlanned(now.toString()); - taskRepresentationModel.setDue(now.toString()); + taskRepresentationModel.setPlanned(now); + taskRepresentationModel.setDue(now); ThrowingCallable httpCall = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_TASKS), - HttpMethod.POST, - new HttpEntity<>(taskRepresentationModel, restHelper.getHeaders()), - ParameterizedTypeReference.forType(TaskRepresentationModel.class)); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_TASKS), + HttpMethod.POST, + new HttpEntity<>(taskRepresentationModel, restHelper.getHeaders()), + ParameterizedTypeReference.forType(TaskRepresentationModel.class)); assertThatThrownBy(httpCall).isInstanceOf(HttpClientErrorException.class); } @@ -744,7 +733,7 @@ class TaskControllerIntTest { // retrieve task from Rest Api ResponseEntity getTaskResponse = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS_ID, claimed_task_id), HttpMethod.GET, new HttpEntity<>(restHelper.getHeadersUser_1_2()), @@ -758,7 +747,7 @@ class TaskControllerIntTest { // cancel claim ResponseEntity cancelClaimResponse = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS_ID_CLAIM, claimed_task_id), HttpMethod.DELETE, new HttpEntity<>(restHelper.getHeadersUser_1_2()), @@ -781,7 +770,7 @@ class TaskControllerIntTest { // retrieve task from Rest Api ResponseEntity responseGet = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_TASKS_ID, claimed_task_id), HttpMethod.GET, new HttpEntity<>(restHelper.getHeadersUser_1_2()), @@ -794,11 +783,12 @@ class TaskControllerIntTest { // try to cancel claim ThrowingCallable httpCall = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_TASKS_ID_CLAIM, claimed_task_id), - HttpMethod.DELETE, - new HttpEntity<>(restHelper.getHeadersUser_1_2()), - ParameterizedTypeReference.forType(TaskRepresentationModel.class)); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_TASKS_ID_CLAIM, claimed_task_id), + HttpMethod.DELETE, + new HttpEntity<>(restHelper.getHeadersUser_1_2()), + ParameterizedTypeReference.forType(TaskRepresentationModel.class)); assertThatThrownBy(httpCall) .extracting(ex -> ((HttpClientErrorException) ex).getStatusCode()) .isEqualTo(HttpStatus.CONFLICT); @@ -812,7 +802,7 @@ class TaskControllerIntTest { // retrieve task from Rest Api ResponseEntity responseGet = - template.exchange( + TEMPLATE.exchange( taskUrlString, HttpMethod.GET, new HttpEntity<>(restHelper.getHeadersUser_1_2()), @@ -828,7 +818,7 @@ class TaskControllerIntTest { final String anyUserName = "dummyUser"; theTaskRepresentationModel.setOwner(anyUserName); ResponseEntity responseUpdate = - template.exchange( + TEMPLATE.exchange( taskUrlString, HttpMethod.PUT, new HttpEntity<>(theTaskRepresentationModel, restHelper.getHeadersUser_1_2()), @@ -848,7 +838,7 @@ class TaskControllerIntTest { // retrieve task from Rest Api ResponseEntity responseGet = - template.exchange( + TEMPLATE.exchange( taskUrlString, HttpMethod.GET, new HttpEntity<>(restHelper.getHeadersUser_1_2()), @@ -865,11 +855,12 @@ class TaskControllerIntTest { theTaskRepresentationModel.setOwner(anyUserName); ThrowingCallable httpCall = - () -> template.exchange( - taskUrlString, - HttpMethod.PUT, - new HttpEntity<>(theTaskRepresentationModel, restHelper.getHeadersUser_1_2()), - ParameterizedTypeReference.forType(TaskRepresentationModel.class)); + () -> + TEMPLATE.exchange( + taskUrlString, + HttpMethod.PUT, + new HttpEntity<>(theTaskRepresentationModel, restHelper.getHeadersUser_1_2()), + ParameterizedTypeReference.forType(TaskRepresentationModel.class)); assertThatThrownBy(httpCall) .isInstanceOf(HttpClientErrorException.class) .hasMessageContaining("409"); @@ -881,8 +872,7 @@ class TaskControllerIntTest { classificationResource.setKey("L11010"); WorkbasketSummaryRepresentationModel workbasketSummary = new WorkbasketSummaryRepresentationModel(); - workbasketSummary.setWorkbasketId( - "WBI:100000000000000000000000000000000004"); + workbasketSummary.setWorkbasketId("WBI:100000000000000000000000000000000004"); ObjectReference objectReference = new ObjectReference(); objectReference.setCompany("MyCompany1"); @@ -893,8 +883,7 @@ class TaskControllerIntTest { TaskRepresentationModel taskRepresentationModel = new TaskRepresentationModel(); taskRepresentationModel.setClassificationSummary(classificationResource); - taskRepresentationModel.setWorkbasketSummary( - workbasketSummary); + taskRepresentationModel.setWorkbasketSummary(workbasketSummary); taskRepresentationModel.setPrimaryObjRef(objectReference); return taskRepresentationModel; } diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssemberTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssemberTest.java index 843920cbc..21856bf99 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssemberTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssemberTest.java @@ -68,12 +68,12 @@ class TaskRepresentationModelAssemberTest { TaskRepresentationModel resource = new TaskRepresentationModel(); resource.setTaskId("taskId"); resource.setExternalId("externalId"); - resource.setCreated("2019-09-13T08:44:17.588Z"); - resource.setClaimed("2019-09-13T08:44:17.588Z"); - resource.setCompleted("2019-09-13T08:44:17.588Z"); - resource.setModified("2019-09-13T08:44:17.588Z"); - resource.setPlanned("2019-09-13T08:44:17.588Z"); - resource.setDue("2019-09-13T08:44:17.588Z"); + resource.setCreated(Instant.parse("2019-09-13T08:44:17.588Z")); + resource.setClaimed(Instant.parse("2019-09-13T08:44:17.588Z")); + resource.setCompleted(Instant.parse("2019-09-13T08:44:17.588Z")); + resource.setModified(Instant.parse("2019-09-13T08:44:17.588Z")); + resource.setPlanned(Instant.parse("2019-09-13T08:44:17.588Z")); + resource.setDue(Instant.parse("2019-09-13T08:44:17.588Z")); resource.setName("name"); resource.setCreator("creator"); resource.setDescription("desc"); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskSummaryAssemblerTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskSummaryAssemblerTest.java index 47345abf6..3dd01a19c 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskSummaryAssemblerTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskSummaryAssemblerTest.java @@ -100,21 +100,11 @@ class TaskSummaryAssemblerTest { void testEquality(TaskSummaryImpl taskSummary, TaskSummaryRepresentationModel resource) { Assert.assertEquals(taskSummary.getId(), resource.getTaskId()); Assert.assertEquals(taskSummary.getExternalId(), resource.getExternalId()); - Assert.assertEquals( - taskSummary.getCreated() == null ? null : taskSummary.getCreated().toString(), - resource.getCreated()); - Assert.assertEquals( - taskSummary.getClaimed() == null ? null : taskSummary.getClaimed().toString(), - resource.getClaimed()); - Assert.assertEquals( - taskSummary.getCompleted() == null ? null : taskSummary.getCompleted().toString(), - resource.getCompleted()); - Assert.assertEquals( - taskSummary.getModified() == null ? null : taskSummary.getModified().toString(), - resource.getModified()); - Assert.assertEquals( - taskSummary.getPlanned() == null ? null : taskSummary.getPlanned().toString(), - resource.getPlanned()); + Assert.assertEquals(taskSummary.getCreated(), resource.getCreated()); + Assert.assertEquals(taskSummary.getClaimed(), resource.getClaimed()); + Assert.assertEquals(taskSummary.getCompleted(), resource.getCompleted()); + Assert.assertEquals(taskSummary.getModified(), resource.getModified()); + Assert.assertEquals(taskSummary.getPlanned(), resource.getPlanned()); Assert.assertEquals(taskSummary.getDescription(), resource.getDescription()); Assert.assertEquals(taskSummary.getName(), resource.getName()); Assert.assertEquals(taskSummary.getCreator(), resource.getCreator()); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketControllerIntTest.java index 4f1fdc895..98028e42d 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketControllerIntTest.java @@ -2,11 +2,11 @@ package pro.taskana.workbasket.rest; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static pro.taskana.common.rest.RestHelper.TEMPLATE; import com.fasterxml.jackson.databind.ObjectMapper; import java.time.Instant; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; @@ -17,7 +17,6 @@ import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; import pro.taskana.common.rest.Mapping; import pro.taskana.common.rest.RestHelper; @@ -42,46 +41,49 @@ class WorkbasketControllerIntTest { WORKBASKET_SUMMARY_PAGE_MODEL_TYPE = new ParameterizedTypeReference< TaskanaPagedModel>() {}; - private static RestTemplate template; - @Autowired RestHelper restHelper; + private final RestHelper restHelper; + private final ObjectMapper mapper; - @BeforeAll - static void init() { - template = RestHelper.TEMPLATE; + @Autowired + WorkbasketControllerIntTest(RestHelper restHelper, ObjectMapper mapper) { + this.restHelper = restHelper; + this.mapper = mapper; } @Test void testGetWorkbasket() { ResponseEntity response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET_ID, "WBI:100000000000000000000000000000000006"), HttpMethod.GET, restHelper.defaultRequest(), ParameterizedTypeReference.forType(WorkbasketRepresentationModel.class)); + assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getHeaders().getContentType().toString()) - .isEqualTo(MediaTypes.HAL_JSON_VALUE); + assertThat(response.getHeaders().getContentType()).isEqualTo(MediaTypes.HAL_JSON); } @Test void testGetAllWorkbaskets() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET), HttpMethod.GET, restHelper.defaultRequest(), WORKBASKET_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); } @Test void testGetAllWorkbasketsBusinessAdminHasOpenPermission() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET) + "?required-permission=OPEN", HttpMethod.GET, restHelper.defaultRequest(), WORKBASKET_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent()).hasSize(3); } @@ -90,11 +92,12 @@ class WorkbasketControllerIntTest { void testGetAllWorkbasketsKeepingFilters() { String parameters = "?type=PERSONAL&sort-by=key&order=desc"; ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET) + parameters, HttpMethod.GET, restHelper.defaultRequest(), WORKBASKET_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat( response @@ -108,11 +111,12 @@ class WorkbasketControllerIntTest { @Test void testThrowsExceptionIfInvalidFilterIsUsed() { ThrowingCallable httpCall = - () -> template.exchange( - restHelper.toUrl(Mapping.URL_WORKBASKET) + "?invalid=PERSONAL", - HttpMethod.GET, - restHelper.defaultRequest(), - WORKBASKET_SUMMARY_PAGE_MODEL_TYPE); + () -> + TEMPLATE.exchange( + restHelper.toUrl(Mapping.URL_WORKBASKET) + "?invalid=PERSONAL", + HttpMethod.GET, + restHelper.defaultRequest(), + WORKBASKET_SUMMARY_PAGE_MODEL_TYPE); assertThatThrownBy(httpCall) .isInstanceOf(HttpClientErrorException.class) .hasMessageContaining("[invalid]") @@ -125,10 +129,8 @@ class WorkbasketControllerIntTest { String workbasketId = "WBI:100000000000000000000000000000000001"; - final ObjectMapper mapper = new ObjectMapper(); - ResponseEntity initialWorkbasketResourceRequestResponse = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET_ID, workbasketId), HttpMethod.GET, new HttpEntity(restHelper.getHeaders()), @@ -137,16 +139,17 @@ class WorkbasketControllerIntTest { WorkbasketRepresentationModel workbasketRepresentationModel = initialWorkbasketResourceRequestResponse.getBody(); + assertThat(workbasketRepresentationModel).isNotNull(); workbasketRepresentationModel.setKey("GPK_KSC"); workbasketRepresentationModel.setDomain("DOMAIN_A"); workbasketRepresentationModel.setType(WorkbasketType.PERSONAL); workbasketRepresentationModel.setName("was auch immer"); workbasketRepresentationModel.setOwner("Joerg"); - workbasketRepresentationModel.setModified(String.valueOf(Instant.now())); + workbasketRepresentationModel.setModified(Instant.now()); ThrowingCallable httpCall = () -> { - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET_ID, workbasketId), HttpMethod.PUT, new HttpEntity<>( @@ -166,7 +169,7 @@ class WorkbasketControllerIntTest { ThrowingCallable httpCall = () -> { - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET_ID, workbasketId), HttpMethod.GET, new HttpEntity(restHelper.getHeaders()), @@ -183,11 +186,12 @@ class WorkbasketControllerIntTest { String parameters = "?sort-by=key&order=desc&page-size=5&page=2"; ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET) + parameters, HttpMethod.GET, restHelper.defaultRequest(), WORKBASKET_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getContent()).hasSize(5); assertThat(response.getBody().getContent().iterator().next().getKey()).isEqualTo("USER_1_1"); assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); @@ -210,7 +214,7 @@ class WorkbasketControllerIntTest { String workbasketID = "WBI:100000000000000000000000000000000005"; ResponseEntity response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET_ID, workbasketID), HttpMethod.DELETE, new HttpEntity<>(restHelper.getHeadersBusinessAdmin()), @@ -224,7 +228,7 @@ class WorkbasketControllerIntTest { ThrowingCallable call = () -> - template.exchange( + TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKET_ID, workbasketWithNonCompletedTasks), HttpMethod.DELETE, new HttpEntity<>(restHelper.getHeadersBusinessAdmin()), @@ -238,7 +242,7 @@ class WorkbasketControllerIntTest { @Test void testRemoveWorkbasketAsDistributionTarget() { ResponseEntity response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl( Mapping.URL_WORKBASKET_ID_DISTRIBUTION, "WBI:100000000000000000000000000000000007"), HttpMethod.DELETE, @@ -247,47 +251,47 @@ class WorkbasketControllerIntTest { assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); ResponseEntity> response2 = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl( Mapping.URL_WORKBASKET_ID_DISTRIBUTION, "WBI:100000000000000000000000000000000002"), HttpMethod.GET, restHelper.defaultRequest(), WORKBASKET_SUMMARY_PAGE_MODEL_TYPE); assertThat(response2.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat( - response2.getBody().getContent().stream() - .map(WorkbasketSummaryRepresentationModel::getWorkbasketId) - .noneMatch("WBI:100000000000000000000000000000000007"::equals)) - .isTrue(); + assertThat(response2.getBody()).isNotNull(); + assertThat(response2.getBody().getContent()) + .extracting(WorkbasketSummaryRepresentationModel::getWorkbasketId) + .doesNotContain("WBI:100000000000000000000000000000000007"); } @Test void testGetWorkbasketAccessItems() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl( Mapping.URL_WORKBASKET_ID_ACCESSITEMS, "WBI:100000000000000000000000000000000005"), HttpMethod.GET, restHelper.defaultRequest(), WORKBASKET_ACCESS_ITEM_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getHeaders().getContentType().toString()) - .isEqualTo(MediaTypes.HAL_JSON_VALUE); + assertThat(response.getHeaders().getContentType()).isEqualTo(MediaTypes.HAL_JSON); assertThat(response.getBody().getContent()).hasSize(3); } @Test void testGetWorkbasketDistributionTargets() { ResponseEntity> response = - template.exchange( + TEMPLATE.exchange( restHelper.toUrl( Mapping.URL_WORKBASKET_ID_DISTRIBUTION, "WBI:100000000000000000000000000000000001"), HttpMethod.GET, restHelper.defaultRequest(), WORKBASKET_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getHeaders().getContentType().toString()) - .isEqualTo(MediaTypes.HAL_JSON_VALUE); + assertThat(response.getHeaders().getContentType()) + .isEqualTo(MediaTypes.HAL_JSON); assertThat(response.getBody().getContent()).hasSize(4); } } diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketDefinitionControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketDefinitionControllerIntTest.java index 8df5292cc..2514e5260 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketDefinitionControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketDefinitionControllerIntTest.java @@ -3,22 +3,21 @@ package pro.taskana.workbasket.rest; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.fail; +import static pro.taskana.common.rest.RestHelper.TEMPLATE; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.List; -import java.util.stream.Collectors; import javax.sql.DataSource; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -34,11 +33,13 @@ import org.springframework.http.ResponseEntity; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.HttpStatusCodeException; import pro.taskana.common.rest.Mapping; import pro.taskana.common.rest.RestHelper; import pro.taskana.common.rest.TaskanaSpringBootTest; +import pro.taskana.common.rest.models.TaskanaPagedModel; +import pro.taskana.common.rest.models.TaskanaPagedModelKeys; import pro.taskana.sampledata.SampleDataGenerator; import pro.taskana.workbasket.rest.models.WorkbasketDefinitionRepresentationModel; @@ -46,20 +47,19 @@ import pro.taskana.workbasket.rest.models.WorkbasketDefinitionRepresentationMode @TaskanaSpringBootTest class WorkbasketDefinitionControllerIntTest { - private static RestTemplate template; + private final ObjectMapper objMapper; + private final RestHelper restHelper; + private final DataSource dataSource; @Value("${taskana.schemaName:TASKANA}") String schemaName; - ObjectMapper objMapper = new ObjectMapper(); - - @Autowired RestHelper restHelper; - - @Autowired private DataSource dataSource; - - @BeforeAll - static void init() { - template = RestHelper.TEMPLATE; + @Autowired + WorkbasketDefinitionControllerIntTest( + ObjectMapper objMapper, RestHelper restHelper, DataSource dataSource) { + this.objMapper = objMapper; + this.restHelper = restHelper; + this.dataSource = dataSource; } @BeforeEach @@ -70,17 +70,18 @@ class WorkbasketDefinitionControllerIntTest { @Test void testExportWorkbasketFromDomain() { - ResponseEntity> response = + ResponseEntity> response = executeExportRequestForDomain("DOMAIN_A"); assertThat(response.getBody()).isNotNull(); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody().get(0)) - .isInstanceOf(WorkbasketDefinitionRepresentationModel.class); + assertThat(response.getBody().getContent()) + .hasOnlyElementsOfType(WorkbasketDefinitionRepresentationModel.class); boolean allAuthorizationsAreEmpty = true; boolean allDistributionTargetsAreEmpty = true; - for (WorkbasketDefinitionRepresentationModel workbasketDefinition : response.getBody()) { + for (WorkbasketDefinitionRepresentationModel workbasketDefinition : + response.getBody().getContent()) { if (allAuthorizationsAreEmpty && !workbasketDefinition.getAuthorizations().isEmpty()) { allAuthorizationsAreEmpty = false; } @@ -98,24 +99,29 @@ class WorkbasketDefinitionControllerIntTest { @Test void testExportWorkbasketsFromWrongDomain() { - ResponseEntity> response = + ResponseEntity> response = executeExportRequestForDomain("wrongDomain"); - assertThat(response.getBody()).isEmpty(); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getContent()).isEmpty(); + assertThat(response.getBody().getKey()).isSameAs(TaskanaPagedModelKeys.WORKBASKET_DEFINITIONS); } @Test void testImportEveryWorkbasketFromDomainA() throws IOException { - List wbList = + TaskanaPagedModel wbList = executeExportRequestForDomain("DOMAIN_A").getBody(); - for (WorkbasketDefinitionRepresentationModel w : wbList) { + assertThat(wbList).isNotNull(); + for (WorkbasketDefinitionRepresentationModel w : wbList.getContent()) { expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.NO_CONTENT, w); } } @Test void testImportWorkbasketWithoutDistributionTargets() throws IOException { - WorkbasketDefinitionRepresentationModel w = - executeExportRequestForDomain("DOMAIN_A").getBody().get(0); + TaskanaPagedModel pagedModel = + executeExportRequestForDomain("DOMAIN_A").getBody(); + assertThat(pagedModel).isNotNull(); + WorkbasketDefinitionRepresentationModel w = pagedModel.getContent().iterator().next(); w.setDistributionTargets(new HashSet<>()); this.expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.NO_CONTENT, w); @@ -127,13 +133,15 @@ class WorkbasketDefinitionControllerIntTest { @Test void testImportWorkbasketWithDistributionTargetsInImportFile() throws IOException { - List wbList = + TaskanaPagedModel wbList = executeExportRequestForDomain("DOMAIN_A").getBody(); + assertThat(wbList).isNotNull(); + Iterator iterator = wbList.getContent().iterator(); - WorkbasketDefinitionRepresentationModel w = wbList.get(0); + WorkbasketDefinitionRepresentationModel w = iterator.next(); w.setDistributionTargets(new HashSet<>()); String letMeBeYourDistributionTarget = w.getWorkbasket().getWorkbasketId(); - WorkbasketDefinitionRepresentationModel w2 = wbList.get(1); + WorkbasketDefinitionRepresentationModel w2 = iterator.next(); w2.setDistributionTargets(Collections.singleton(letMeBeYourDistributionTarget)); expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.NO_CONTENT, w, w2); @@ -150,11 +158,14 @@ class WorkbasketDefinitionControllerIntTest { @Test void testImportWorkbasketWithDistributionTargetsInSystem() throws IOException { - List wbList = + TaskanaPagedModel wbList = executeExportRequestForDomain("DOMAIN_A").getBody(); - wbList.removeIf(definition -> definition.getDistributionTargets().isEmpty()); - WorkbasketDefinitionRepresentationModel w = wbList.get(0); + assertThat(wbList).isNotNull(); + List content = new ArrayList<>(wbList.getContent()); + + content.removeIf(definition -> definition.getDistributionTargets().isEmpty()); + WorkbasketDefinitionRepresentationModel w = content.iterator().next(); expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.NO_CONTENT, w); changeWorkbasketIdOrKey(w, null, "new"); @@ -163,50 +174,58 @@ class WorkbasketDefinitionControllerIntTest { @Test void testImportWorkbasketWithDistributionTargetsNotInSystem() throws IOException { - List wbList = + TaskanaPagedModel wbList = executeExportRequestForDomain("DOMAIN_A").getBody(); - WorkbasketDefinitionRepresentationModel w = wbList.get(0); + assertThat(wbList).isNotNull(); + WorkbasketDefinitionRepresentationModel w = wbList.getContent().iterator().next(); w.setDistributionTargets(Collections.singleton("invalidWorkbasketId")); - try { - expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.BAD_REQUEST, w); - fail("Expected http-Status 400"); - } catch (HttpClientErrorException e) { - assertThat(e.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); - } + ThrowingCallable httpCall = + () -> expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.BAD_REQUEST, w); + assertThatThrownBy(httpCall) + .isInstanceOf(HttpClientErrorException.class) + .extracting(e -> (HttpClientErrorException) e) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); w.getWorkbasket().setKey("anotherNewKey"); - try { - expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.BAD_REQUEST, w); - fail("Expected http-Status 400"); - } catch (HttpClientErrorException e) { - assertThat(e.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); - } + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpClientErrorException.class) + .extracting(e -> (HttpClientErrorException) e) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); } @Test void testFailOnImportDuplicates() throws IOException { - WorkbasketDefinitionRepresentationModel w = - executeExportRequestForDomain("DOMAIN_A").getBody().get(0); - try { - expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.CONFLICT, w, w); - fail("Expected http-Status 409"); - } catch (HttpClientErrorException e) { - assertThat(e.getStatusCode()).isEqualTo(HttpStatus.CONFLICT); - } + TaskanaPagedModel pagedModel = + executeExportRequestForDomain("DOMAIN_A").getBody(); + + assertThat(pagedModel).isNotNull(); + WorkbasketDefinitionRepresentationModel w = pagedModel.getContent().iterator().next(); + ThrowingCallable httpCall = + () -> expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.CONFLICT, w, w); + assertThatThrownBy(httpCall) + .isInstanceOf(HttpClientErrorException.class) + .extracting(e -> (HttpClientErrorException) e) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.CONFLICT); } @Test void testNoErrorWhenImportWithSameIdButDifferentKeyAndDomain() throws IOException { - List wbList = + TaskanaPagedModel wbList = executeExportRequestForDomain("DOMAIN_A").getBody(); - WorkbasketDefinitionRepresentationModel w = wbList.get(0); - WorkbasketDefinitionRepresentationModel differentLogicalId = wbList.get(1); + assertThat(wbList).isNotNull(); + Iterator iterator = wbList.getContent().iterator(); + WorkbasketDefinitionRepresentationModel w = iterator.next(); + WorkbasketDefinitionRepresentationModel differentLogicalId = iterator.next(); this.changeWorkbasketIdOrKey(differentLogicalId, w.getWorkbasket().getWorkbasketId(), null); // breaks the logic but not the script- should we really allow this case? - WorkbasketDefinitionRepresentationModel theDestroyer = wbList.get(2); + WorkbasketDefinitionRepresentationModel theDestroyer = iterator.next(); theDestroyer.setDistributionTargets( Collections.singleton(differentLogicalId.getWorkbasket().getWorkbasketId())); @@ -216,16 +235,15 @@ class WorkbasketDefinitionControllerIntTest { @Test void testErrorWhenImportWithSameAccessIdAndWorkbasket() { - WorkbasketDefinitionRepresentationModel w = - executeExportRequestForDomain("DOMAIN_A").getBody().get(0); + TaskanaPagedModel pagedModel = + executeExportRequestForDomain("DOMAIN_A").getBody(); + + assertThat(pagedModel).isNotNull(); + WorkbasketDefinitionRepresentationModel w = pagedModel.getContent().iterator().next(); - String w1String = workbasketToString(w); - w.getWorkbasket().setKey("new Key for this WB"); - String w2String = workbasketToString(w); ThrowingCallable httpCall = () -> { - expectStatusWhenExecutingImportRequestOfWorkbaskets( - HttpStatus.CONFLICT, Arrays.asList(w1String, w2String)); + expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.CONFLICT, w, w); }; assertThatThrownBy(httpCall).isInstanceOf(HttpClientErrorException.class); } @@ -242,30 +260,33 @@ class WorkbasketDefinitionControllerIntTest { } } - private ResponseEntity> + private ResponseEntity> executeExportRequestForDomain(String domain) { - return template.exchange( + return TEMPLATE.exchange( restHelper.toUrl(Mapping.URL_WORKBASKETDEFIITIONS) + "?domain=" + domain, HttpMethod.GET, restHelper.defaultRequest(), - new ParameterizedTypeReference>() {}); + new ParameterizedTypeReference< + TaskanaPagedModel>() {}); } private void expectStatusWhenExecutingImportRequestOfWorkbaskets( HttpStatus expectedStatus, WorkbasketDefinitionRepresentationModel... workbaskets) throws IOException { - List workbasketStrings = - Arrays.stream(workbaskets).map(this::workbasketToString).collect(Collectors.toList()); - expectStatusWhenExecutingImportRequestOfWorkbaskets(expectedStatus, workbasketStrings); + TaskanaPagedModel pagedModel = + new TaskanaPagedModel<>( + TaskanaPagedModelKeys.WORKBASKET_DEFINITIONS, Arrays.asList(workbaskets)); + expectStatusWhenExecutingImportRequestOfWorkbaskets(expectedStatus, pagedModel); } private void expectStatusWhenExecutingImportRequestOfWorkbaskets( - HttpStatus expectedStatus, List workbasketStrings) throws IOException { + HttpStatus expectedStatus, + TaskanaPagedModel pageModel) + throws IOException { File tmpFile = File.createTempFile("test", ".tmp"); - OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tmpFile), UTF_8); - writer.write(workbasketStrings.toString()); - writer.close(); - + try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tmpFile), UTF_8)) { + objMapper.writeValue(writer, pageModel); + } MultiValueMap body = new LinkedMultiValueMap<>(); HttpHeaders headers = restHelper.getHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); @@ -275,16 +296,7 @@ class WorkbasketDefinitionControllerIntTest { String serverUrl = restHelper.toUrl(Mapping.URL_WORKBASKETDEFIITIONS); ResponseEntity responseImport = - template.postForEntity(serverUrl, requestEntity, Void.class); + TEMPLATE.postForEntity(serverUrl, requestEntity, Void.class); assertThat(responseImport.getStatusCode()).isEqualTo(expectedStatus); } - - private String workbasketToString( - WorkbasketDefinitionRepresentationModel workbasketDefinitionRepresentationModel) { - try { - return objMapper.writeValueAsString(workbasketDefinitionRepresentationModel); - } catch (JsonProcessingException e) { - return ""; - } - } } diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/assembler/WorkbasketRepresentationModelAssemblerTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/assembler/WorkbasketRepresentationModelAssemblerTest.java index 10dca158f..2c5fafa4e 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/assembler/WorkbasketRepresentationModelAssemblerTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/assembler/WorkbasketRepresentationModelAssemblerTest.java @@ -18,8 +18,16 @@ import pro.taskana.workbasket.rest.models.WorkbasketRepresentationModel; @TaskanaSpringBootTest class WorkbasketRepresentationModelAssemblerTest { - @Autowired WorkbasketService workbasketService; - @Autowired WorkbasketRepresentationModelAssembler workbasketRepresentationModelAssembler; + private final WorkbasketService workbasketService; + private final WorkbasketRepresentationModelAssembler workbasketRepresentationModelAssembler; + + @Autowired + WorkbasketRepresentationModelAssemblerTest( + WorkbasketService workbasketService, + WorkbasketRepresentationModelAssembler workbasketRepresentationModelAssembler) { + this.workbasketService = workbasketService; + this.workbasketRepresentationModelAssembler = workbasketRepresentationModelAssembler; + } @Test void workbasketToResource() { @@ -53,7 +61,7 @@ class WorkbasketRepresentationModelAssemblerTest { // given WorkbasketRepresentationModel resource = new WorkbasketRepresentationModel(); resource.setWorkbasketId("1"); - resource.setModified("2010-01-01T12:00:00Z"); + resource.setModified(Instant.parse("2010-01-01T12:00:00Z")); resource.setType(WorkbasketType.PERSONAL); // when Workbasket workbasket = workbasketRepresentationModelAssembler.toEntityModel(resource); @@ -66,7 +74,7 @@ class WorkbasketRepresentationModelAssemblerTest { // given WorkbasketRepresentationModel resource = new WorkbasketRepresentationModel(); resource.setWorkbasketId("1"); - resource.setCreated("2010-01-01T12:00:00Z"); + resource.setCreated(Instant.parse("2010-01-01T12:00:00Z")); resource.setType(WorkbasketType.PERSONAL); // when Workbasket workbasket = workbasketRepresentationModelAssembler.toEntityModel(resource); @@ -80,8 +88,8 @@ class WorkbasketRepresentationModelAssemblerTest { WorkbasketRepresentationModel workbasketRepresentationModel = new WorkbasketRepresentationModel(); workbasketRepresentationModel.setWorkbasketId("1"); - workbasketRepresentationModel.setCreated("2010-01-01T12:00:00Z"); - workbasketRepresentationModel.setModified("2010-01-01T12:00:00Z"); + workbasketRepresentationModel.setCreated(Instant.parse("2010-01-01T12:00:00Z")); + workbasketRepresentationModel.setModified(Instant.parse("2010-01-01T12:00:00Z")); workbasketRepresentationModel.setCustom1("Custom1"); workbasketRepresentationModel.setCustom2("Custom2"); workbasketRepresentationModel.setCustom3("Custom3"); @@ -124,9 +132,9 @@ class WorkbasketRepresentationModelAssemblerTest { assertThat(workbasketRepresentationModel.getWorkbasketId()).isEqualTo(workbasket.getId()); assertThat(workbasketRepresentationModel.getKey()).isEqualTo(workbasket.getKey()); assertThat(workbasketRepresentationModel.getCreated()) - .isEqualTo(workbasket.getCreated() == null ? null : workbasket.getCreated().toString()); + .isEqualTo(workbasket.getCreated()); assertThat(workbasketRepresentationModel.getModified()) - .isEqualTo(workbasket.getModified() == null ? null : workbasket.getModified().toString()); + .isEqualTo(workbasket.getModified()); assertThat(workbasketRepresentationModel.getName()).isEqualTo(workbasket.getName()); assertThat(workbasketRepresentationModel.getDescription()) .isEqualTo(workbasket.getDescription());