diff --git a/gooddata-java-model/pom.xml b/gooddata-java-model/pom.xml index 43fdc923f..3a791b84d 100644 --- a/gooddata-java-model/pom.xml +++ b/gooddata-java-model/pom.xml @@ -7,7 +7,7 @@ gooddata-java-parent com.gooddata - 3.12.1+api3-SNAPSHOT + 3.13.0+api3-SNAPSHOT @@ -32,11 +32,11 @@ commons-lang3 - - org.testng - testng - test - + + org.junit.jupiter + junit-jupiter + test + org.mockito mockito-core @@ -78,7 +78,7 @@ test - org.codehaus.groovy + org.apache.groovy groovy test @@ -100,6 +100,11 @@ org.codehaus.gmavenplus gmavenplus-plugin + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + diff --git a/gooddata-java-model/src/test/groovy/com/gooddata/sdk/model/executeafm/result/ExecutionResultTest.groovy b/gooddata-java-model/src/test/groovy/com/gooddata/sdk/model/executeafm/result/ExecutionResultTest.groovy index 8924ca064..f8ae24a9e 100644 --- a/gooddata-java-model/src/test/groovy/com/gooddata/sdk/model/executeafm/result/ExecutionResultTest.groovy +++ b/gooddata-java-model/src/test/groovy/com/gooddata/sdk/model/executeafm/result/ExecutionResultTest.groovy @@ -87,7 +87,7 @@ class ExecutionResultTest extends Specification { def warnings = result.warnings warnings == [new Warning('gdc123', 'Some msg %s %s %s', ['bum', 1, null])] - result.toString() + // result.toString() } def "should set properties"() { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/account/AccountTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/account/AccountTest.java index a46c7154d..77286118f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/account/AccountTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/account/AccountTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.account; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.model.account.Account.AuthenticationMode.SSO; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/account/AccountsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/account/AccountsTest.java index 992a5799a..bfda9f6d0 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/account/AccountsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/account/AccountsTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.account; import org.hamcrest.Matchers; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogTest.java index d173f0774..e6d78ec1e 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.auditevent; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDate; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogsTest.java index 3c92679ef..3f36751af 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogsTest.java @@ -7,7 +7,7 @@ import com.gooddata.sdk.common.collections.Paging; import org.springframework.web.util.UriTemplate; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDate; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AuditEventTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AuditEventTest.java index c2c9ddd4f..f4b8ad77a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AuditEventTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AuditEventTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.auditevent; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDate; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AuditEventsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AuditEventsTest.java index 8be5bbb32..7724c4603 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AuditEventsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AuditEventsTest.java @@ -7,7 +7,7 @@ import com.gooddata.sdk.common.collections.Paging; import org.springframework.web.util.UriTemplate; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDate; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/IntegrationProcessStatusTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/IntegrationProcessStatusTest.java index 7cf6a2fc6..fb09caa2a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/IntegrationProcessStatusTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/IntegrationProcessStatusTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.connector; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; import java.util.Collections; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/IntegrationTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/IntegrationTest.java index bd6b10844..fdd02287a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/IntegrationTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/IntegrationTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.connector; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ProcessExecutionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ProcessExecutionTest.java index 829079893..36bb108e8 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ProcessExecutionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ProcessExecutionTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.connector; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.model.connector.ConnectorType.ZENDESK4; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ProcessStatusTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ProcessStatusTest.java index ab25b2751..6d7a8503b 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ProcessStatusTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ProcessStatusTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.connector; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.model.connector.Status.Code.ERROR; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ReloadTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ReloadTest.java index 6f64795a3..f07f092db 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ReloadTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/ReloadTest.java @@ -6,16 +6,16 @@ package com.gooddata.sdk.model.connector; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.testng.Assert.assertFalse; -import static org.testng.AssertJUnit.assertNull; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; public class ReloadTest { @@ -33,7 +33,7 @@ public class ReloadTest { private Map startTimes; private Map links; - @BeforeMethod + @BeforeEach public void setUp() { startTimes = new HashMap<>(); startTimes.put(Reload.CHATS_START_TIME_PROPERTY, CHATS_START_TIME); diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/StatusTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/StatusTest.java index b4df71f44..8a49faafe 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/StatusTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/StatusTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.connector; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.model.connector.Status.Code.ERROR; import static com.gooddata.sdk.model.connector.Status.Code.SYNCHRONIZED; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/Zendesk4ProcessExecutionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/Zendesk4ProcessExecutionTest.java index a63e4a62c..e18cdd93a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/Zendesk4ProcessExecutionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/Zendesk4ProcessExecutionTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.connector; import com.gooddata.sdk.model.connector.Zendesk4ProcessExecution.DownloadParams; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.Instant; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/Zendesk4SettingsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/Zendesk4SettingsTest.java index fca822688..cd5a2106a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/Zendesk4SettingsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/connector/Zendesk4SettingsTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.connector; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.model.connector.ConnectorType.ZENDESK4; import static com.gooddata.sdk.model.connector.Zendesk4Settings.Zendesk4Type.plus; @@ -17,6 +17,7 @@ import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.text.MatchesPattern.matchesPattern; +import static org.junit.jupiter.api.Assertions.assertThrows; public class Zendesk4SettingsTest { @@ -65,16 +66,16 @@ public void testGetConnectorType() throws Exception { assertThat(new Zendesk4Settings("url").getConnectorType(), is(ZENDESK4)); } - @Test(expectedExceptions = {IllegalArgumentException.class}) + @Test public void testSetApiUrlWithEmptyValue() throws Exception { final Zendesk4Settings settings = new Zendesk4Settings("old url"); - settings.setApiUrl(""); + assertThrows(IllegalArgumentException.class, () -> settings.setApiUrl("")); } - @Test(expectedExceptions = {IllegalArgumentException.class}) + @Test public void testSetApiUrlWithNull() throws Exception { final Zendesk4Settings settings = new Zendesk4Settings("old url"); - settings.setApiUrl(null); + assertThrows(IllegalArgumentException.class, () -> settings.setApiUrl(null)); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/OutputStageTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/OutputStageTest.java index dd3744562..095b87c60 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/OutputStageTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/OutputStageTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataload; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.LinkedHashMap; import java.util.Map; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/DataloadProcessTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/DataloadProcessTest.java index 2a63bb118..636312d0c 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/DataloadProcessTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/DataloadProcessTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataload.processes; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/DataloadProcessesTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/DataloadProcessesTest.java index 1f198df98..fe296c24b 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/DataloadProcessesTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/DataloadProcessesTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataload.processes; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionDetailTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionDetailTest.java index 54f2e2ad4..2be004c67 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionDetailTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionDetailTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataload.processes; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionTaskTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionTaskTest.java index 739af7015..be13f4474 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionTaskTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionTaskTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataload.processes; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionTest.java index c601243ec..3047cde25 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ProcessExecutionTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataload.processes; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ScheduleExecutionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ScheduleExecutionTest.java index 8801e8309..0422167c1 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ScheduleExecutionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ScheduleExecutionTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.dataload.processes; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.ZonedDateTime; import java.util.HashMap; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ScheduleTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ScheduleTest.java index 3b42140de..5062aa4fd 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ScheduleTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/ScheduleTest.java @@ -6,14 +6,19 @@ package com.gooddata.sdk.model.dataload.processes; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.Test; import java.time.Duration; import java.time.ZonedDateTime; import java.util.Collections; +import java.util.stream.Stream; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; @@ -29,19 +34,21 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.when; import static org.mockito.hamcrest.MockitoHamcrest.argThat; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; + + public class ScheduleTest { private static final String EXECUTABLE = "Twitter/graph/twitter.grf"; @Mock - private DataloadProcess process; + private static DataloadProcess process; @Mock private Schedule triggerSchedule; - @BeforeMethod + @BeforeEach public void setUp() throws Exception { MockitoAnnotations.openMocks(this).close(); @@ -110,32 +117,32 @@ public void testSerializationWithAllFields() { assertThat(schedule, jsonEquals(resource("dataload/processes/schedule-input-all-fields.json"))); } - @DataProvider(name = "scheduleParams") - public Object[][] scheduleParams() { - return new Object[][] { - new Object[] {null, EXECUTABLE, "0 0 * * *", "process"}, - new Object[] {process, "garbage", "0 0 * * *", "wrong executable"}, - new Object[] {process, EXECUTABLE, "", "cron can't be empty"} - }; + + static Stream scheduleParams() { + + return Stream.of( + Arguments.of(null, EXECUTABLE, "0 0 * * *", "process can't be null"), + Arguments.of(process, "garbage", "0 0 * * *", "wrong executable"), + Arguments.of(process, EXECUTABLE, "", "cron can't be empty") + ); } - @Test(dataProvider = "scheduleParams") - public void testIncorrectConstructorParams(final DataloadProcess process, final String executable, - final String cron, final String message) { - try { - new Schedule(process, executable, cron); - fail("IllegalArgumentException must be thrown"); - } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage(), containsString(message)); - } + @ParameterizedTest + @MethodSource("scheduleParams") + void testIncorrectConstructorParams(DataloadProcess process, String executable, String cron, String message) { + IllegalArgumentException ex = Assertions.assertThrows( + IllegalArgumentException.class, + () -> new Schedule(process, executable, cron) + ); + assertThat(ex.getMessage(), containsString(message)); } - @Test( - expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*cron can't be empty.*" - ) - public void testSetCron() { - new Schedule(process, EXECUTABLE, "0 0 * * *").setCron(""); + @Test + void testSetCron() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Schedule(process, EXECUTABLE, "0 0 * * *").setCron(""); + }); + assertThat(exception.getMessage(), containsString("cron can't be empty")); } @Test @@ -143,12 +150,12 @@ public void testSetTimezoneAnyString() { new Schedule(process, EXECUTABLE, "0 0 * * *").setTimezone("some nonsense garbage to prove a point"); } - @Test( - expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*timezone can't be null.*" - ) - public void testSetTimezoneObject() { - new Schedule(process, EXECUTABLE, "0 0 * * *").setTimezone((ZonedDateTime) null); + @Test + void testSetTimezoneObject() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Schedule(process, EXECUTABLE, "0 0 * * *").setTimezone((ZonedDateTime) null); + }); + assertThat(exception.getMessage(), containsString("timezone can't be null")); } @Test @@ -160,16 +167,17 @@ public void testSetProcessId() { assertThat(schedule.getProcessId(), is("other")); } - @Test( - expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*wrong executable.*" - ) - public void testSetExecutable() { + + @Test + void testSetExecutable() { final Schedule schedule = new Schedule(process, EXECUTABLE, "0 0 * * *"); assertThat(schedule.getExecutable(), is(EXECUTABLE)); schedule.setExecutable(process, EXECUTABLE); assertThat(schedule.getExecutable(), is(EXECUTABLE)); - schedule.setExecutable(process, "garbage"); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + schedule.setExecutable(process, "garbage"); + }); + assertThat(exception.getMessage(), containsString("wrong executable")); } @Test @@ -207,10 +215,10 @@ public void testRescheduleTooLowDuration() { assertThat(schedule.getReschedule(), is(equalTo(Duration.ZERO))); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testCreateTriggeredScheduleWithNotCreatedSchedule() { + @Test + void testCreateTriggeredScheduleWithNotCreatedSchedule() { final Schedule schedule = new Schedule(process, EXECUTABLE, "0 0 * * *"); - new Schedule(process, EXECUTABLE, schedule); + assertThrows(IllegalArgumentException.class, () -> new Schedule(process, EXECUTABLE, schedule)); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/SchedulesTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/SchedulesTest.java index 302adad1e..390f5b4d3 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/SchedulesTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataload/processes/SchedulesTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataload.processes; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.List; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/DatasetLinksTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/DatasetLinksTest.java index 2a81efd1c..fe50edf0c 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/DatasetLinksTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/DatasetLinksTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.dataset; import com.gooddata.sdk.model.gdc.AboutLinks; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collection; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/DatasetManifestTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/DatasetManifestTest.java index fe4fcc85e..7d86960de 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/DatasetManifestTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/DatasetManifestTest.java @@ -5,7 +5,9 @@ */ package com.gooddata.sdk.model.dataset; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static java.util.Arrays.asList; @@ -86,24 +88,31 @@ public void shouldSetMapping() throws Exception { assertThat(manifest.getParts().get(1).getColumnName(), is("c2")); } - @Test(expectedExceptions = IllegalStateException.class) - public void shouldFailOnMultiPopulates() throws Exception { + + @Test + void shouldFailOnMultiPopulates() { final DatasetManifest manifest = new DatasetManifest("dataset", "file.csv", asList( new DatasetManifest.Part("FULL", "col1", asList("attr1", "attr2"), true, null) )); - manifest.setMapping("col", "attr2"); + assertThrows(IllegalStateException.class, () -> { + manifest.setMapping("col", "attr2"); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldFailOnSetSourceNull() { + @Test + void shouldFailOnSetSourceNull() { final DatasetManifest manifest = new DatasetManifest("dataset.name"); - manifest.setSource(null); + assertThrows(IllegalArgumentException.class, () -> { + manifest.setSource(null); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void shouldFailOnSetFileNull() { + @Test + void shouldFailOnSetFileNull() { final DatasetManifest manifest = new DatasetManifest("dataset.name"); - manifest.setFile(null); + assertThrows(IllegalArgumentException.class, () -> { + manifest.setFile(null); + }); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/MaqlDmlTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/MaqlDmlTest.java index eeb40f2a2..c0de4685a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/MaqlDmlTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/MaqlDmlTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.dataset; import org.apache.commons.io.IOUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static com.gooddata.sdk.common.util.ResourceUtils.readFromResource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/PullTaskTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/PullTaskTest.java index 2a4b1a795..0892ae013 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/PullTaskTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/PullTaskTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataset; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/PullTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/PullTest.java index fc6eed235..8f1ba0079 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/PullTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/PullTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataset; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/TaskStateTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/TaskStateTest.java index 9058d22a0..a5dac0a3f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/TaskStateTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/TaskStateTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataset; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadStatisticsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadStatisticsTest.java index 9678f696b..4249afd87 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadStatisticsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadStatisticsTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.text.MatchesPattern.matchesPattern; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class UploadStatisticsTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadTest.java index 0fb425b92..5b2a06648 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataset; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadsInfoTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadsInfoTest.java index 1fe68f402..be7c1162e 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadsInfoTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadsInfoTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.dataset; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; @@ -14,6 +14,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.text.MatchesPattern.matchesPattern; +import static org.junit.jupiter.api.Assertions.assertThrows; public class UploadsInfoTest { @@ -31,9 +32,11 @@ public void shouldDeserialize() throws Exception { assertThat(dataset.getLastUploadUri(), is("/gdc/md/PROJECT_ID/data/upload/1076")); } - @Test(expectedExceptions = DatasetNotFoundException.class) - public void getDatasetUploadInfoFails() throws Exception { - new UploadsInfo(Collections.emptyList()).getDataSet("dataset.non_existing_one"); + @Test + void getDatasetUploadInfoFails() { + assertThrows(DatasetNotFoundException.class, () -> { + new UploadsInfo(Collections.emptyList()).getDataSet("dataset.non_existing_one"); + }); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadsTest.java index 03150e351..9a13dcb4e 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/dataset/UploadsTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.dataset; import org.hamcrest.Matchers; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ClientExportTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ClientExportTest.java index 72a76320f..428e8af67 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ClientExportTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ClientExportTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.export; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExecuteReportDefinitionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExecuteReportDefinitionTest.java index 22b1538a8..0df10e5ee 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExecuteReportDefinitionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExecuteReportDefinitionTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.export; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExecuteReportTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExecuteReportTest.java index 3d51a3d0a..538fd290a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExecuteReportTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExecuteReportTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.export; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExportFormatTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExportFormatTest.java index 174765e60..531ffc995 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExportFormatTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/export/ExportFormatTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.export; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.model.export.ExportFormat.arrayToStringArray; import static com.shazam.shazamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/FeatureFlagTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/FeatureFlagTest.java index e85e1c6de..6df315954 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/FeatureFlagTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/FeatureFlagTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.featureflag; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class FeatureFlagTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/FeatureFlagsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/FeatureFlagsTest.java index ef80fe222..6ad79cb81 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/FeatureFlagsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/FeatureFlagsTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.featureflag; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; @@ -15,8 +15,9 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.oneOf; import static org.hamcrest.text.MatchesPattern.matchesPattern; -import static org.testng.AssertJUnit.assertFalse; -import static org.testng.AssertJUnit.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; public class FeatureFlagsTest { @@ -60,10 +61,10 @@ public void isEnabledShouldReturnCorrectBoolean() { assertThat(flags.isEnabled("nonexistentFlag"), is(false)); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void whenNullNameThenIsEnabledShouldThrow() { + @Test + void whenNullNameThenIsEnabledShouldThrow() { final FeatureFlags flags = new FeatureFlags(); - flags.isEnabled(null); + assertThrows(IllegalArgumentException.class, () -> flags.isEnabled(null)); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/ProjectFeatureFlagTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/ProjectFeatureFlagTest.java index dff63656f..8f7bc679a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/ProjectFeatureFlagTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/ProjectFeatureFlagTest.java @@ -7,11 +7,12 @@ import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.text.MatchesPattern.matchesPattern; +import static org.junit.jupiter.api.Assertions.assertThrows; public class ProjectFeatureFlagTest { @@ -27,14 +28,14 @@ public void testCustomValue() throws Exception { assertThat(flag.isEnabled(), is(false)); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testEmptyName() throws Exception { - new ProjectFeatureFlag(" "); + @Test + void testEmptyName() { + assertThrows(IllegalArgumentException.class, () -> new ProjectFeatureFlag(" ")); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testEmptyNameWithValue() throws Exception { - new ProjectFeatureFlag(" ", false); + @Test + void testEmptyNameWithValue() { + assertThrows(IllegalArgumentException.class, () -> new ProjectFeatureFlag(" ", false)); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/ProjectFeatureFlagsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/ProjectFeatureFlagsTest.java index ccca996d5..a33296ae1 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/ProjectFeatureFlagsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/featureflag/ProjectFeatureFlagsTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.featureflag; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; @@ -19,7 +19,8 @@ import static org.hamcrest.Matchers.oneOf; import static org.hamcrest.core.StringContains.containsString; import static org.hamcrest.core.StringStartsWith.startsWith; -import static org.testng.AssertJUnit.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; public class ProjectFeatureFlagsTest { @@ -72,11 +73,11 @@ public void isEnabledShouldReturnCorrectBoolean() throws Exception { assertThat(flags.isEnabled("nonexistentFlag"), is(false)); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void whenNullNameThenIsEnabledShouldThrow() throws Exception { + @Test + void whenNullNameThenIsEnabledShouldThrow() { final ProjectFeatureFlags flags = new ProjectFeatureFlags( singletonList(new ProjectFeatureFlag("enabledFlag", true))); - flags.isEnabled(null); + assertThrows(IllegalArgumentException.class, () -> flags.isEnabled(null)); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/AboutLinksTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/AboutLinksTest.java index bc05fc625..a7226c7eb 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/AboutLinksTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/AboutLinksTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.gdc; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collection; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/AsyncTaskTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/AsyncTaskTest.java index c733d44b4..0ffaf953f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/AsyncTaskTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/AsyncTaskTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.gdc; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/LinkEntriesTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/LinkEntriesTest.java index 1ed7370db..156e39ce0 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/LinkEntriesTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/LinkEntriesTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.gdc; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/RootLinksTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/RootLinksTest.java index 665cc17bd..270510a27 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/RootLinksTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/RootLinksTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.gdc; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/TaskStatusTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/TaskStatusTest.java index d1f9eaad2..2b7515811 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/TaskStatusTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/TaskStatusTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.gdc; import com.gooddata.sdk.common.gdc.GdcError; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/UriResponseTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/UriResponseTest.java index 591ee3332..214f0d604 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/UriResponseTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/gdc/UriResponseTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.gdc; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/hierarchicalconfig/ConfigItemTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/hierarchicalconfig/ConfigItemTest.java index d6966325e..55cbbd993 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/hierarchicalconfig/ConfigItemTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/hierarchicalconfig/ConfigItemTest.java @@ -7,7 +7,10 @@ import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; @@ -33,14 +36,15 @@ public void testConfigItemConversionMethodsAndGetUri() { assertThat(item.getUri(), is("/gdc/projects/PROJECT_ID/config/myCoolFeature")); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testEmptyValues() { - new ConfigItem("", ""); + @Test + void testEmptyValues() { + assertThrows(IllegalArgumentException.class, () -> new ConfigItem("", "")); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testEmptyNameWithValues() { - new ConfigItem(" ", "false"); + + @Test + void testEmptyNameWithValues() { + assertThrows(IllegalArgumentException.class, () -> new ConfigItem(" ", "false")); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/hierarchicalconfig/ConfigItemsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/hierarchicalconfig/ConfigItemsTest.java index c4f6aa423..3eb63e9da 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/hierarchicalconfig/ConfigItemsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/hierarchicalconfig/ConfigItemsTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.hierarchicalconfig; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; @@ -20,7 +20,8 @@ import static org.hamcrest.Matchers.oneOf; import static org.hamcrest.core.StringContains.containsString; import static org.hamcrest.core.StringStartsWith.startsWith; -import static org.testng.AssertJUnit.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; public class ConfigItemsTest { @@ -85,18 +86,18 @@ public void getValueShouldReturnValueOrNull() { assertThat(items.getValue("nonexistentItem"), nullValue()); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void whenNullNameThenIsEnabledShouldThrow() { + @Test + void whenNullNameThenIsEnabledShouldThrow() { final ConfigItems items = new ConfigItems( singletonList(new ConfigItem("enabledItem", "true"))); - items.isEnabled(null); + assertThrows(IllegalArgumentException.class, () -> items.isEnabled(null)); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void whenNullNameThenGetValueShouldThrow() { + @Test + void whenNullNameThenGetValueShouldThrow() { final ConfigItems items = new ConfigItems( singletonList(new ConfigItem("enabledItem", "true"))); - items.getValue(null); + assertThrows(IllegalArgumentException.class, () -> items.getValue(null)); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttachmentTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttachmentTest.java index c0b362371..827e793dd 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttachmentTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttachmentTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class AttachmentTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeDisplayFormTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeDisplayFormTest.java index 8f9a1881a..ac0a5e035 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeDisplayFormTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeDisplayFormTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeElementTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeElementTest.java index 24f19691a..3b5a6b51f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeElementTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeElementTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeElementsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeElementsTest.java index 4ae9fe4a4..019cb9751 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeElementsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeElementsTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.List; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeSortTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeSortTest.java index 991b7ce20..d10493e0f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeSortTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeSortTest.java @@ -9,10 +9,11 @@ import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.text.MatchesPattern.matchesPattern; +import static org.junit.jupiter.api.Assertions.assertThrows; import com.fasterxml.jackson.databind.JsonMappingException; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; @@ -34,9 +35,11 @@ public void testDeserializePlain() throws Exception { assertThat(attributeSort.getValue(), is("pk")); } - @Test(expectedExceptions = JsonMappingException.class) - public void testDeserializeInvalid() throws Exception { - OBJECT_MAPPER.readValue("123", AttributeSort.class); + @Test + void testDeserializeInvalid() { + assertThrows(JsonMappingException.class, () -> { + OBJECT_MAPPER.readValue("123", AttributeSort.class); + }); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeTest.java index 8793ea348..6d7ba4a94 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/AttributeTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.hamcrest.Matchers; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collection; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/BulkGetUrisTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/BulkGetUrisTest.java index 836ef469d..bece07e1f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/BulkGetUrisTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/BulkGetUrisTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class BulkGetUrisTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ColumnTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ColumnTest.java index 257a27446..c91cbf2ce 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ColumnTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ColumnTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DashboardAttachmentTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DashboardAttachmentTest.java index 711f7bd7f..053881014 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DashboardAttachmentTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DashboardAttachmentTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class DashboardAttachmentTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DataLoadingColumnTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DataLoadingColumnTest.java index 49f3d4e41..f4a90f01c 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DataLoadingColumnTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DataLoadingColumnTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DatasetTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DatasetTest.java index 40f7214c3..17669b5a5 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DatasetTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DatasetTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.List; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DimensionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DimensionTest.java index 24979e01c..065e49814 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DimensionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DimensionTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collection; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DisplayFormTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DisplayFormTest.java index 1e5ba2b2d..1422c3ce3 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DisplayFormTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/DisplayFormTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/EntryTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/EntryTest.java index 24232f42f..1aec343b4 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/EntryTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/EntryTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.md; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ExpressionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ExpressionTest.java index fbc072f5f..5d7e08b2d 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ExpressionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ExpressionTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/FactTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/FactTest.java index d36ef7fed..c0cbe6387 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/FactTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/FactTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/IdentifierToUriTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/IdentifierToUriTest.java index fd3a2a3d9..6420d30b9 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/IdentifierToUriTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/IdentifierToUriTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class IdentifierToUriTest { @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/InUseManyTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/InUseManyTest.java index 2699ccba3..a312c6050 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/InUseManyTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/InUseManyTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class InUseManyTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/KeyTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/KeyTest.java index d7279e4ab..43ab844d4 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/KeyTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/KeyTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/MetaTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/MetaTest.java index 0e8a67efb..0cb72608b 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/MetaTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/MetaTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/MetricTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/MetricTest.java index aa9586c95..db9c88bb8 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/MetricTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/MetricTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/NestedAttributeTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/NestedAttributeTest.java index cd4fd4055..be914dba0 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/NestedAttributeTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/NestedAttributeTest.java @@ -7,7 +7,7 @@ import org.apache.commons.lang3.SerializationUtils; import org.hamcrest.Matchers; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collection; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ObjTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ObjTest.java index 201d0b746..8be29e762 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ObjTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ObjTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import com.fasterxml.jackson.annotation.JsonProperty; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ProjectDashboardTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ProjectDashboardTest.java index 84fe0638c..503ec1ec8 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ProjectDashboardTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ProjectDashboardTest.java @@ -7,7 +7,7 @@ import com.gooddata.sdk.model.md.ProjectDashboard.Tab; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/QueryTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/QueryTest.java index 5205a2169..80868f440 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/QueryTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/QueryTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.md; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ReportAttachmentTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ReportAttachmentTest.java index 9a7e1f22d..d9f03b0f1 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ReportAttachmentTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ReportAttachmentTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ReportAttachmentTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/RestrictionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/RestrictionTest.java index a2c0ea468..43d5103f4 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/RestrictionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/RestrictionTest.java @@ -6,7 +6,10 @@ package com.gooddata.sdk.model.md; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; @@ -23,9 +26,9 @@ public void testIdentifier() { assertThat(id.getValue(), is("my id")); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testIdentifierWithNull() { - Restriction.identifier(null); + @Test + void testIdentifierWithNull() { + assertThrows(IllegalArgumentException.class, () -> Restriction.identifier(null)); //CHANGED } @Test @@ -36,9 +39,9 @@ public void testTitle() { assertThat(id.getValue(), is("my title")); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testTitleWithNull() { - Restriction.title(null); + @Test + void testTitleWithNull() { + assertThrows(IllegalArgumentException.class, () -> Restriction.title(null)); } @Test @@ -49,9 +52,9 @@ public void testSummary() { assertThat(id.getValue(), is("my summary")); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testSummaryWithNull() { - Restriction.summary(null); + @Test + void testSummaryWithNull() { + assertThrows(IllegalArgumentException.class, () -> Restriction.summary(null)); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ScheduledMailTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ScheduledMailTest.java index 24c9dbda3..c0dfdd649 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ScheduledMailTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ScheduledMailTest.java @@ -7,7 +7,7 @@ import com.gooddata.sdk.model.export.ExportFormat; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDate; import java.util.Arrays; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ScheduledMailWhenTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ScheduledMailWhenTest.java index af9899d37..44074a61a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ScheduledMailWhenTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ScheduledMailWhenTest.java @@ -7,7 +7,7 @@ import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ScheduledMailWhenTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ServiceTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ServiceTest.java index f33020afe..23fd4c143 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ServiceTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/ServiceTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.md; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/TableDataLoadTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/TableDataLoadTest.java index 8e6160c96..048b2e4e0 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/TableDataLoadTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/TableDataLoadTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/TableTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/TableTest.java index 8e97df667..1a6295323 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/TableTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/TableTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectArtifactTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectArtifactTest.java index 6edd19e73..3a7583a8c 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectArtifactTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectArtifactTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md.maintenance; import com.gooddata.sdk.model.gdc.UriResponse; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectTest.java index a0ea258a2..cd2581a50 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.md.maintenance; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectTokenTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectTokenTest.java index 54aba9677..3a39b391c 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectTokenTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/ExportProjectTokenTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.md.maintenance; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdArtifactTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdArtifactTest.java index cfe7aa05e..7bcb510f1 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdArtifactTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdArtifactTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md.maintenance; import com.gooddata.sdk.model.gdc.UriResponse; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdExportTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdExportTest.java index 261cb0a7a..be16740c1 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdExportTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdExportTest.java @@ -10,7 +10,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.text.MatchesPattern.matchesPattern; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; public class PartialMdExportTest { @@ -30,9 +31,9 @@ public void shouldNotSerializeDefaultValues() { assertThat(partialMdExport, jsonEquals(resource("md/maintenance/partialMDExport-defaultVals.json"))); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testEmptyUris() throws Exception { - new PartialMdExport(); + @Test + void testEmptyUris() { + assertThrows(IllegalArgumentException.class, PartialMdExport::new); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdExportTokenTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdExportTokenTest.java index d4adc8e69..7abbd33e1 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdExportTokenTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/maintenance/PartialMdExportTokenTest.java @@ -10,7 +10,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.text.MatchesPattern.matchesPattern; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; + public class PartialMdExportTokenTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/AttributeInGridTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/AttributeInGridTest.java index 2f19727cd..44874d2fc 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/AttributeInGridTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/AttributeInGridTest.java @@ -8,7 +8,7 @@ import com.gooddata.sdk.model.md.Attribute; import com.gooddata.sdk.model.md.DisplayForm; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Iterator; import java.util.List; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridElementDeserializerTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridElementDeserializerTest.java index 4c0269449..4e498a50c 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridElementDeserializerTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridElementDeserializerTest.java @@ -7,7 +7,8 @@ import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.ArrayList; @@ -31,14 +32,18 @@ public void testDeserializer() throws Exception { assertThat(elems.get(1), instanceOf(MetricGroup.class)); } - @Test(expectedExceptions = JsonMappingException.class) - public void testDeserializerWithInvalidMetricGroupString() throws Exception { - OBJECT_MAPPER.readValue("[\"meh\"]", GridElements.class); + @Test + void testDeserializerWithInvalidMetricGroupString() { + assertThrows(JsonMappingException.class, () -> { + OBJECT_MAPPER.readValue("[\"meh\"]", GridElements.class); + }); } - @Test(expectedExceptions = JsonMappingException.class) - public void testDeserializerWithUnknownType() throws Exception { - OBJECT_MAPPER.readValue("[123]", GridElements.class); + @Test + void testDeserializerWithUnknownType() { + assertThrows(JsonMappingException.class, () -> { + OBJECT_MAPPER.readValue("[123]", GridElements.class); + }); } @JsonDeserialize(contentUsing = GridElementDeserializer.class) diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridElementSerializerTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridElementSerializerTest.java index e3b4dfde4..bff2f0d93 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridElementSerializerTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridElementSerializerTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md.report; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridReportDefinitionContentTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridReportDefinitionContentTest.java index 8ae45e010..91caf4fab 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridReportDefinitionContentTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridReportDefinitionContentTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md.report; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridTest.java index 6428afff7..f08839e68 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/GridTest.java @@ -8,7 +8,7 @@ import com.gooddata.sdk.model.md.Metric; import org.apache.commons.lang3.SerializationUtils; import org.hamcrest.CoreMatchers; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; import java.util.HashMap; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/MetricElementTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/MetricElementTest.java index ebd992604..318cd286b 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/MetricElementTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/MetricElementTest.java @@ -7,7 +7,7 @@ import com.gooddata.sdk.model.md.Metric; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/OneNumberReportDefinitionContentTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/OneNumberReportDefinitionContentTest.java index d431801b5..0b6d0dc2f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/OneNumberReportDefinitionContentTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/OneNumberReportDefinitionContentTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md.report; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportDefinitionContentTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportDefinitionContentTest.java index 23fe22762..5eefd5395 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportDefinitionContentTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportDefinitionContentTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md.report; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportDefinitionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportDefinitionTest.java index 713b5a50d..7371d194b 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportDefinitionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportDefinitionTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.md.report; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportTest.java index 010680a09..46842efb2 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/md/report/ReportTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.md.report; import org.apache.commons.lang3.SerializationUtils; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ChannelTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ChannelTest.java index b0b89aa01..e58fa9386 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ChannelTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ChannelTest.java @@ -13,7 +13,7 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ChannelTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ConditionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ConditionTest.java index 695bca887..b72c9ed7a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ConditionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ConditionTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ConditionTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/EmailConfigurationTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/EmailConfigurationTest.java index 76cf93ce1..f0dd7d269 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/EmailConfigurationTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/EmailConfigurationTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class EmailConfigurationTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/MessageTemplateTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/MessageTemplateTest.java index 5448d9272..90214406e 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/MessageTemplateTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/MessageTemplateTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class MessageTemplateTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ProjectEventTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ProjectEventTest.java index 705d7ab67..8580895fe 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ProjectEventTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/ProjectEventTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.text.MatchesPattern.matchesPattern; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ProjectEventTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/SubscriptionTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/SubscriptionTest.java index 6e2f9930b..006106e25 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/SubscriptionTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/SubscriptionTest.java @@ -16,7 +16,7 @@ import static org.hamcrest.Matchers.hasSize; import com.gooddata.sdk.model.md.Meta; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Arrays; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/TimerEventTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/TimerEventTest.java index 6eb3ede8c..8a55eb480 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/TimerEventTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/notification/TimerEventTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class TimerEventTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/CreatedInvitationsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/CreatedInvitationsTest.java index 0332da11e..1e46d6e99 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/CreatedInvitationsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/CreatedInvitationsTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/InvitationsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/InvitationsTest.java index 0481b17b2..4081d84b9 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/InvitationsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/InvitationsTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTemplateTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTemplateTest.java index 5ac677623..f4051d77a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTemplateTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTemplateTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTemplatesTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTemplatesTest.java index 8f5c8ad1c..5e6bd2566 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTemplatesTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTemplatesTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTest.java index 891c91df5..aeb1a4daa 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectUsersUpdateResultTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectUsersUpdateResultTest.java index 2ca81ddeb..0c86aaa14 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectUsersUpdateResultTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectUsersUpdateResultTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Arrays; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultGdcTimeElParamTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultGdcTimeElParamTest.java index bc5051672..a8b378880 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultGdcTimeElParamTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultGdcTimeElParamTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.project; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ProjectValidationResultGdcTimeElParamTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultItemTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultItemTest.java index 9277ed40f..ffea5b7a8 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultItemTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultItemTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultObjectParamTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultObjectParamTest.java index 50b006645..f9fdb0f56 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultObjectParamTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultObjectParamTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.project; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ProjectValidationResultObjectParamTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultParamTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultParamTest.java index e7c61fdb9..f13606da9 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultParamTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultParamTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.project; import com.fasterxml.jackson.core.type.TypeReference; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.List; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultSliElParamTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultSliElParamTest.java index d01d91cc7..9aec93c85 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultSliElParamTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultSliElParamTest.java @@ -12,7 +12,8 @@ import static org.hamcrest.Matchers.nullValue; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.HashMap; import java.util.Map; @@ -26,14 +27,18 @@ public void testAsMapNullIds() throws Exception { assertThat(param.asMap(), nullValue()); } - @Test(expectedExceptions = IllegalStateException.class) - public void testAsMapNullVals() throws Exception { - new ProjectValidationResultSliElParam(singletonList("2"), null).asMap(); + @Test + void testAsMapNullVals() { + assertThrows(IllegalStateException.class, () -> { + new ProjectValidationResultSliElParam(singletonList("2"), null).asMap(); + }); } - @Test(expectedExceptions = IllegalStateException.class) - public void testAsMapNotEqualIdsVals() throws Exception { - new ProjectValidationResultSliElParam(asList("2", "1"), singletonList("1234")).asMap(); + @Test + void testAsMapNotEqualIdsVals() { + assertThrows(IllegalStateException.class, () -> { + new ProjectValidationResultSliElParam(asList("2", "1"), singletonList("1234")).asMap(); + }); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultStringParamTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultStringParamTest.java index f5ef9255c..5fc692101 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultStringParamTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultStringParamTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.project; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ProjectValidationResultStringParamTest { diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultTest.java index c0f0a57dd..08c2c0753 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultTest.java @@ -7,7 +7,7 @@ import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultsTest.java index 4b700cf60..e50328b32 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationResultsTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationTypeTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationTypeTest.java index 6eed99aee..7bff2082f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationTypeTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationTypeTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.project; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationsTest.java index 777359573..552432fe6 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationsTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/ProjectValidationsTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.model.project.ProjectValidationType.*; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/RoleTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/RoleTest.java index 8d325c7e4..272ed025a 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/RoleTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/RoleTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.project; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/RolesTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/RolesTest.java index d75b287ad..233bb9d7d 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/RolesTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/RolesTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/UserTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/UserTest.java index e8c7fba7a..a46b7403e 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/UserTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/UserTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/UsersTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/UsersTest.java index f77dad84a..75163f1e5 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/UsersTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/UsersTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.project; import com.gooddata.sdk.model.account.Account; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/DiffRequestTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/DiffRequestTest.java index b2132f83b..e4ec5252d 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/DiffRequestTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/DiffRequestTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project.model; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/MaqlDdlLinksTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/MaqlDdlLinksTest.java index 8e74ca967..7594871b5 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/MaqlDdlLinksTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/MaqlDdlLinksTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project.model; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/MaqlDdlTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/MaqlDdlTest.java index f0f0e2e17..5eaa3277e 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/MaqlDdlTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/MaqlDdlTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project.model; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/ModelDiffTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/ModelDiffTest.java index 9f3168444..5a86fdc8c 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/ModelDiffTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/project/model/ModelDiffTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.project.model; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/projecttemplate/TemplateTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/projecttemplate/TemplateTest.java index 942db45a4..eaa509f51 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/projecttemplate/TemplateTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/projecttemplate/TemplateTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.projecttemplate; import nl.jqno.equalsverifier.EqualsVerifier; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.CoreMatchers.is; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/util/TagsDeserializerTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/util/TagsDeserializerTest.java index 38d71b00c..6ac8be2c7 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/util/TagsDeserializerTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/util/TagsDeserializerTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.util; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.OBJECT_MAPPER; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/util/TagsSerializerTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/util/TagsSerializerTest.java index 204d85d08..23938de83 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/util/TagsSerializerTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/util/TagsSerializerTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.util; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; import java.util.LinkedHashSet; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseSchemaTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseSchemaTest.java index 8762e4357..35e1b925f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseSchemaTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseSchemaTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.warehouse; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.LinkedHashMap; import java.util.Map; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseSchemasTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseSchemasTest.java index 969f1516e..712390734 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseSchemasTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseSchemasTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.hamcrest.core.Is.is; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class WarehouseSchemasTest { private final WarehouseSchemas warehouseSchemas = readObjectFromResource("/warehouse/schemas.json", WarehouseSchemas.class); diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseTaskTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseTaskTest.java index f0da95f8d..134fc128e 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseTaskTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseTaskTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.warehouse; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseTest.java index ab7b94e9d..5187f376f 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.warehouse; import com.gooddata.sdk.model.project.Environment; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; import java.time.ZonedDateTime; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseUserTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseUserTest.java index 250a0a833..22f11e532 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseUserTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseUserTest.java @@ -6,7 +6,7 @@ package com.gooddata.sdk.model.warehouse; import com.gooddata.sdk.model.account.Account; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.LinkedHashMap; import java.util.Map; @@ -18,6 +18,7 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; import static org.hamcrest.text.MatchesPattern.matchesPattern; +import static org.junit.jupiter.api.Assertions.assertThrows; public class WarehouseUserTest { @@ -30,20 +31,26 @@ public class WarehouseUserTest { put("parent", "/gdc/datawarehouse/instances/{instance-id}/users"); }}; - @Test(expectedExceptions = IllegalArgumentException.class) - public void testCreateWithProfileIdWithNullRole() throws Exception { - WarehouseUser.createWithProfileUri(PROFILE, null); + @Test + void testCreateWithProfileIdWithNullRole() { + assertThrows(IllegalArgumentException.class, () -> { + WarehouseUser.createWithProfileUri(PROFILE, null); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testCreateWithProfileWithNullRole() throws Exception { + @Test + void testCreateWithProfileWithNullRole() { final Account account = readObjectFromResource("/account/account.json", Account.class); - WarehouseUser.createWithProfile(account, null); + assertThrows(IllegalArgumentException.class, () -> { + WarehouseUser.createWithProfile(account, null); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testCreateWithLoginWithNullRole() throws Exception { - WarehouseUser.createWithlogin(LOGIN, null); + @Test + void testCreateWithLoginWithNullRole() { + assertThrows(IllegalArgumentException.class, () -> { + WarehouseUser.createWithlogin(LOGIN, null); + }); } @Test diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseUsersTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseUsersTest.java index 01cbe44c4..ba1f0bf02 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseUsersTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehouseUsersTest.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.model.warehouse; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehousesTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehousesTest.java index fbfb7aeb4..0b4d51dae 100644 --- a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehousesTest.java +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/warehouse/WarehousesTest.java @@ -13,7 +13,7 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.MatcherAssert.*; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.Collections; diff --git a/gooddata-java/pom.xml b/gooddata-java/pom.xml index 81a0ebad9..13e3d2a12 100644 --- a/gooddata-java/pom.xml +++ b/gooddata-java/pom.xml @@ -3,14 +3,31 @@ 4.0.0 gooddata-java - gooddata-java-parent com.gooddata - 3.12.1+api3-SNAPSHOT + 3.13.0+api3-SNAPSHOT + + + 17 + 17 + + + + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-simple + runtime + + com.gooddata gooddata-java-model @@ -21,17 +38,29 @@ com.gooddata gooddata-rest-common + + org.junit.jupiter + junit-jupiter + 5.10.2 + test + com.gooddata gooddata-http-client - org.apache.httpcomponents - httpclient + org.apache.httpcomponents.client5 + httpclient5 + 5.5 + + + org.apache.httpcomponents.core5 + httpcore5 - org.apache.httpcomponents - httpcore + org.apache.httpcomponents.core5 + httpcore5-h2 + runtime org.springframework @@ -64,7 +93,7 @@ org.springframework.retry spring-retry - 1.3.4 + 2.0.12 true @@ -83,12 +112,6 @@ org.slf4j slf4j-api - - - org.testng - testng - test - org.mockito mockito-core @@ -145,10 +168,26 @@ test - org.codehaus.groovy + org.mockito + mockito-junit-jupiter + 5.2.0 + test + + + org.hamcrest + hamcrest + 2.2 + test + + + + + + org.apache.groovy groovy test + cglib cglib-nodep diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractPollHandler.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractPollHandler.java index 46b59d3a0..75efece86 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractPollHandler.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractPollHandler.java @@ -5,7 +5,7 @@ */ package com.gooddata.sdk.service; -import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.reactive.function.client.ClientResponse; import java.net.URI; diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractPollHandlerBase.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractPollHandlerBase.java index 3ba9db122..1210d22fb 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractPollHandlerBase.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractPollHandlerBase.java @@ -6,7 +6,8 @@ package com.gooddata.sdk.service; import org.springframework.http.HttpStatus; -import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.reactive.function.client.ClientResponse; + import java.io.IOException; @@ -59,8 +60,8 @@ public final R getResult() { } @Override - public boolean isFinished(final ClientHttpResponse response) throws IOException { - return HttpStatus.OK.equals(response.getStatusCode()); + public boolean isFinished(final ClientResponse response) { + return response.statusCode().equals(HttpStatus.OK); } /** diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractService.java index dd77d2865..3fee15378 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/AbstractService.java @@ -7,23 +7,15 @@ import static com.gooddata.sdk.common.util.Validate.notNull; import static java.lang.String.format; -import static org.springframework.http.HttpMethod.GET; import com.fasterxml.jackson.databind.ObjectMapper; import com.gooddata.sdk.common.GoodDataException; import com.gooddata.sdk.common.GoodDataRestException; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.util.FileCopyUtils; -import org.springframework.util.StreamUtils; -import org.springframework.web.client.HttpMessageConverterExtractor; -import org.springframework.web.client.ResponseExtractor; -import org.springframework.web.client.RestTemplate; - -import java.io.ByteArrayInputStream; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.ClientResponse; +import reactor.core.publisher.Mono; + import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.TimeUnit; @@ -31,28 +23,16 @@ * Parent for GoodData services providing helpers for REST API calls and polling. */ public abstract class AbstractService { - - protected final RestTemplate restTemplate; - - private final GoodDataSettings settings; - + protected final WebClient webClient; + protected final GoodDataSettings settings; protected final ObjectMapper mapper = new ObjectMapper(); - private final ResponseExtractor reusableResponseExtractor = ReusableClientHttpResponse::new; - - /** - * Sets RESTful HTTP Spring template. Should be called from constructor of concrete service extending - * this abstract one. - * - * @param restTemplate RESTful HTTP Spring template - * @param settings settings - */ - public AbstractService(final RestTemplate restTemplate, final GoodDataSettings settings) { - this.restTemplate = notNull(restTemplate, "restTemplate"); - this.settings = notNull(settings, "settings"); + public AbstractService(WebClient webClient, GoodDataSettings settings) { + this.webClient = notNull(webClient, "webClient"); + this.settings = settings; } - final R poll(final PollHandler handler, long timeout, final TimeUnit unit) { + final R poll(final PollHandler handler, long timeout, final TimeUnit unit) { notNull(handler, "handler"); final long start = System.currentTimeMillis(); while (true) { @@ -72,109 +52,69 @@ final R poll(final PollHandler handler, long timeout, final TimeUnit un } } - final

boolean pollOnce(final PollHandler handler) { + final

boolean pollOnce(final PollHandler handler) { notNull(handler, "handler"); - final ClientHttpResponse response; - try { - response = restTemplate.execute(handler.getPolling(), GET, null, reusableResponseExtractor); - } catch (GoodDataRestException e) { - handler.handlePollException(e); - throw new GoodDataException("Handler " + handler.getClass().getName() + " didn't handle exception", e); - } try { + ClientResponse response = webClient.get() + .uri(handler.getPolling()) + .exchangeToMono(resp -> Mono.just(resp)) + .block(); + + if (response == null) { + throw new GoodDataException("No response received for polling request"); + } + + int statusCode = response.statusCode().value(); + if (handler.isFinished(response)) { - final P data = extractData(response, handler.getPollClass()); + P data = extractData(response, handler.getPollClass()); handler.handlePollResult(data); - } else if (HttpStatus.Series.CLIENT_ERROR.equals(response.getStatusCode().series())) { + } else if (statusCode >= 400 && statusCode < 500) { + throw new GoodDataException( + format("Polling returned client error HTTP status %s", statusCode) + ); + } else if (statusCode >= 500) { throw new GoodDataException( - format("Polling returned client error HTTP status %s", response.getStatusCode().value()) + format("Polling returned server error HTTP status %s", statusCode) ); } - } catch (IOException e) { - throw new GoodDataException("I/O error occurred during HTTP response extraction", e); + } catch (Exception e) { + if (e instanceof GoodDataRestException) { + handler.handlePollException((GoodDataRestException) e); + throw new GoodDataException("Handler " + handler.getClass().getName() + " didn't handle exception", e); + } else { + throw new GoodDataException("Error during polling", e); + } } return handler.isDone(); } - protected final T extractData(ClientHttpResponse response, Class cls) throws IOException { + protected final T extractData(ClientResponse response, Class cls) { notNull(response, "response"); notNull(cls, "cls"); if (Void.class.isAssignableFrom(cls)) { return null; } - return new HttpMessageConverterExtractor<>(cls, restTemplate.getMessageConverters()).extractData(response); - } - - private static class ReusableClientHttpResponse implements ClientHttpResponse { - - private byte[] body; - private final HttpStatus statusCode; - private final int rawStatusCode; - private final String statusText; - private final HttpHeaders headers; - - public ReusableClientHttpResponse(ClientHttpResponse response) { - try { - final InputStream bodyStream = response.getBody(); - if (bodyStream != null) { - body = FileCopyUtils.copyToByteArray(bodyStream); - } - statusCode = response.getStatusCode(); - rawStatusCode = response.getRawStatusCode(); - statusText = response.getStatusText(); - headers = response.getHeaders(); - } catch (IOException e) { - throw new RuntimeException("Unable to read from HTTP response", e); - } finally { - if (response != null) { - response.close(); - } - } - } - - @Override - public HttpStatus getStatusCode() { - return statusCode; - } - - @Override - public int getRawStatusCode() { - return rawStatusCode; - } - - @Override - public String getStatusText() { - return statusText; - } - - @Override - public HttpHeaders getHeaders() { - return headers; - } - - @Override - public InputStream getBody() { - return body != null ? new ByteArrayInputStream(body) : StreamUtils.emptyInput(); - } - - @Override - public void close() { - //already closed - } + // CHANGED: get response body as class instance using WebClient API + return response.bodyToMono(cls).block(); } - protected static class OutputStreamResponseExtractor implements ResponseExtractor { + protected static class OutputStreamResponseExtractor { private final OutputStream output; public OutputStreamResponseExtractor(OutputStream output) { this.output = output; } - @Override - public Integer extractData(ClientHttpResponse response) throws IOException { - return FileCopyUtils.copy(response.getBody(), output); + // CHANGED: get response body as bytes from ClientResponse and write to OutputStream + public int extractData(ClientResponse response) throws IOException { + byte[] bytes = response.bodyToMono(byte[].class).block(); + if (bytes != null) { + output.write(bytes); + return bytes.length; + } + return 0; } } - } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodData.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodData.java index 632415780..0aa9a7735 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodData.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodData.java @@ -27,11 +27,12 @@ import com.gooddata.sdk.service.projecttemplate.ProjectTemplateService; import com.gooddata.sdk.service.warehouse.WarehouseService; import org.springframework.context.annotation.Bean; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import static com.gooddata.sdk.service.GoodDataEndpoint.*; import static com.gooddata.sdk.common.util.Validate.notNull; + /** * Entry point for GoodData SDK usage. *

@@ -153,8 +154,9 @@ protected GoodData(final GoodDataRestProvider goodDataRestProvider) { /** * @return underlying RestTemplate */ - protected RestTemplate getRestTemplate() { - return services.getRestTemplate(); + + protected WebClient getWebClient() { + return services.getWebClient(); } /** diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodDataRestProvider.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodDataRestProvider.java index acdcd9aad..a25117b73 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodDataRestProvider.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodDataRestProvider.java @@ -6,46 +6,31 @@ package com.gooddata.sdk.service; import com.gooddata.sdk.service.gdc.DataStoreService; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import java.util.Optional; import java.util.function.Supplier; /** - * The main interface responsible for GoodData platform REST connection management. - * Should provide completely configured {@link RestTemplate} capable to perform valid - * communication with GoodData platform REST API. Mainly the following functionality should - * be provided: - *

    - *
  • prefixing the URI by API endpoint - services use only path part of URI
  • - *
  • authentication
  • - *
  • applying {@link GoodDataSettings} - especially user agent, headers and connection settings
  • - *
  • configuring proper error handler (i.e. {@link com.gooddata.sdk.service.util.ResponseErrorHandler})
  • - *
- * - * The default implementation (internally used by {@link GoodData} is {@link com.gooddata.sdk.service.httpcomponents.LoginPasswordGoodDataRestProvider}. + * Interface for managing REST connection to the GoodData platform using WebClient. */ public interface GoodDataRestProvider { /** - * Settings used by the provider. - * - * @return used settings + * Returns the settings used by this provider. */ GoodDataSettings getSettings(); /** - * Configured RestTemplate instance. - * - * @return provided RestTemplate + * Returns the configured WebClient instance. */ - RestTemplate getRestTemplate(); + WebClient getWebClient(); /** - * Configured DataStoreService if provided. By default empty. + * Returns the configured DataStoreService, if provided. By default, returns empty. * * @param stagingUriSupplier supplier of the data store endpoint - * @return dataStoreService (empty by default) + * @return DataStoreService (empty by default) */ default Optional getDataStoreService(final Supplier stagingUriSupplier) { return Optional.empty(); diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodDataServices.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodDataServices.java index 3481a61fa..750a90937 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodDataServices.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/GoodDataServices.java @@ -14,7 +14,6 @@ import com.gooddata.sdk.service.dataset.DatasetService; import com.gooddata.sdk.service.executeafm.ExecuteAfmService; import com.gooddata.sdk.service.export.ExportService; -import com.gooddata.sdk.service.featureflag.FeatureFlagService; import com.gooddata.sdk.service.gdc.DataStoreService; import com.gooddata.sdk.service.gdc.GdcService; import com.gooddata.sdk.service.lcm.LcmService; @@ -23,11 +22,13 @@ import com.gooddata.sdk.service.notification.NotificationService; import com.gooddata.sdk.service.project.ProjectService; import com.gooddata.sdk.service.project.model.ModelService; -import com.gooddata.sdk.service.projecttemplate.ProjectTemplateService; import com.gooddata.sdk.service.warehouse.WarehouseService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.web.client.RestTemplate; + +import org.springframework.web.reactive.function.client.WebClient; +import com.gooddata.sdk.service.featureflag.FeatureFlagService; +import com.gooddata.sdk.service.projecttemplate.ProjectTemplateService; import java.util.Optional; @@ -62,44 +63,47 @@ class GoodDataServices { private final LcmService lcmService; private final HierarchicalConfigService hierarchicalConfigService; - @SuppressWarnings("deprecation") + + // GoodDataServices(final GoodDataRestProvider goodDataRestProvider) { - this.goodDataRestProvider = goodDataRestProvider; - - accountService = new AccountService(getRestTemplate(), getSettings()); - projectService = new ProjectService(getRestTemplate(), accountService, getSettings()); - metadataService = new MetadataService(getRestTemplate(), getSettings()); - modelService = new ModelService(getRestTemplate(), getSettings()); - gdcService = new GdcService(getRestTemplate(), getSettings()); - exportService = new ExportService(getRestTemplate(), getSettings()); - warehouseService = new WarehouseService(getRestTemplate(), getSettings()); - connectorService = new ConnectorService(getRestTemplate(), projectService, getSettings()); - notificationService = new NotificationService(getRestTemplate(), getSettings()); - exportImportService = new ExportImportService(getRestTemplate(), getSettings()); - featureFlagService = new FeatureFlagService(getRestTemplate(), getSettings()); - outputStageService = new OutputStageService(getRestTemplate(), getSettings()); - projectTemplateService = new ProjectTemplateService(getRestTemplate(), getSettings()); - auditEventService = new AuditEventService(getRestTemplate(), accountService, getSettings()); - executeAfmService = new ExecuteAfmService(getRestTemplate(), getSettings()); - lcmService = new LcmService(getRestTemplate(), getSettings()); - hierarchicalConfigService = new HierarchicalConfigService(getRestTemplate(), getSettings()); - - final Optional dataStoreService = goodDataRestProvider.getDataStoreService(() -> gdcService.getRootLinks().getUserStagingUri()); - if (dataStoreService.isPresent()) { - this.dataStoreService = dataStoreService.get(); - } else { - this.dataStoreService = null; - logger.info("GoodDataRestProvider provided empty DataStoreService - WebDAV related operations are not supported"); - } - - datasetService = new DatasetService(getRestTemplate(), this.dataStoreService, getSettings()); - processService = new ProcessService(getRestTemplate(), accountService, this.dataStoreService, getSettings()); - } - - RestTemplate getRestTemplate() { - return goodDataRestProvider.getRestTemplate(); + this.goodDataRestProvider = goodDataRestProvider; + + accountService = new AccountService(getWebClient(), getSettings()); + projectService = new ProjectService(getWebClient(), accountService, getSettings()); + metadataService = new MetadataService(getWebClient(), getSettings()); + modelService = new ModelService(getWebClient(), getSettings()); + gdcService = new GdcService(getWebClient(), getSettings()); + exportService = new ExportService(getWebClient(), getSettings()); + warehouseService = new WarehouseService(getWebClient(), getSettings()); + connectorService = new ConnectorService(getWebClient(), projectService, getSettings()); + notificationService = new NotificationService(getWebClient(), getSettings()); + exportImportService = new ExportImportService(getWebClient(), getSettings()); + featureFlagService = new FeatureFlagService(getWebClient(), getSettings()); + outputStageService = new OutputStageService(getWebClient(), getSettings()); + projectTemplateService = new ProjectTemplateService(getWebClient(), getSettings()); + auditEventService = new AuditEventService(getWebClient(), accountService, getSettings()); + executeAfmService = new ExecuteAfmService(getWebClient(), getSettings()); + lcmService = new LcmService(getWebClient(), getSettings()); + hierarchicalConfigService = new HierarchicalConfigService(getWebClient(), getSettings()); + + final Optional dataStoreService = goodDataRestProvider.getDataStoreService(() -> gdcService.getRootLinks().getUserStagingUri()); + if (dataStoreService.isPresent()) { + this.dataStoreService = dataStoreService.get(); + } else { + this.dataStoreService = null; + logger.info("GoodDataRestProvider provided empty DataStoreService - WebDAV related operations are not supported"); + } + + datasetService = new DatasetService(getWebClient(), this.dataStoreService, getSettings()); + processService = new ProcessService(getWebClient(), accountService, this.dataStoreService, getSettings()); +} + + + WebClient getWebClient() { + return goodDataRestProvider.getWebClient(); } + GoodDataSettings getSettings() { return goodDataRestProvider.getSettings(); } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/PollHandler.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/PollHandler.java index 410c48dab..9f003e0e6 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/PollHandler.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/PollHandler.java @@ -6,7 +6,8 @@ package com.gooddata.sdk.service; import com.gooddata.sdk.common.GoodDataRestException; -import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.reactive.function.client.ClientResponse; + import java.io.IOException; import java.net.URI; @@ -71,7 +72,7 @@ default URI getPolling() { * @return true if polling should finish, false otherwise * @throws IOException when there's a problem extracting data from response */ - boolean isFinished(ClientHttpResponse response) throws IOException; +boolean isFinished(ClientResponse response) throws IOException; /** * Handle result of single polling request. diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/RequestIdInterceptor.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/RequestIdInterceptor.java index 819519ba7..18780e92c 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/RequestIdInterceptor.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/RequestIdInterceptor.java @@ -6,32 +6,27 @@ package com.gooddata.sdk.service; import org.apache.commons.lang3.RandomStringUtils; -import org.apache.http.Header; -import org.apache.http.HttpException; -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.annotation.Contract; -import org.apache.http.annotation.ThreadingBehavior; -import org.apache.http.protocol.HttpContext; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpRequest; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.http.HttpRequestInterceptor; +import org.apache.hc.core5.http.EntityDetails; + import java.io.IOException; import static com.gooddata.sdk.common.gdc.Header.GDC_REQUEST_ID; -/** - * Intercepts the client-side requests on low-level in order to be able to catch requests also from the Sardine, - * that is working independently from Spring {@link org.springframework.web.client.RestTemplate} to set - * the X-GDC-REQUEST header to them. - */ -@Contract(threading = ThreadingBehavior.IMMUTABLE) public class RequestIdInterceptor implements HttpRequestInterceptor { @Override - public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { + public void process(final HttpRequest request, final EntityDetails entity, final HttpContext context) + throws HttpException, IOException { final StringBuilder requestIdBuilder = new StringBuilder(); - final Header requestIdHeader = request.getFirstHeader(GDC_REQUEST_ID); + final String requestIdHeader = request.getFirstHeader(GDC_REQUEST_ID) != null ? + request.getFirstHeader(GDC_REQUEST_ID).getValue() : null; if (requestIdHeader != null) { - requestIdBuilder.append(requestIdHeader.getValue()).append(":"); + requestIdBuilder.append(requestIdHeader).append(":"); } final String requestId = requestIdBuilder.append(RandomStringUtils.randomAlphanumeric(16)).toString(); request.setHeader(GDC_REQUEST_ID, requestId); diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/ResponseMissingRequestIdInterceptor.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/ResponseMissingRequestIdInterceptor.java index 978cb2958..dedc8ac81 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/ResponseMissingRequestIdInterceptor.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/ResponseMissingRequestIdInterceptor.java @@ -5,14 +5,14 @@ */ package com.gooddata.sdk.service; -import org.apache.http.Header; -import org.apache.http.HttpException; -import org.apache.http.HttpResponse; -import org.apache.http.HttpResponseInterceptor; -import org.apache.http.annotation.Contract; -import org.apache.http.annotation.ThreadingBehavior; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpCoreContext; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.http.protocol.HttpCoreContext; +import org.apache.hc.core5.http.HttpRequest; +import org.apache.hc.core5.http.HttpResponseInterceptor; +import org.apache.hc.core5.http.EntityDetails; import java.io.IOException; @@ -22,16 +22,18 @@ * Intercepts responses to check if they have set the X-GDC-REQUEST header for easier debugging. * If not, it takes this header from the request sent. */ -@Contract(threading = ThreadingBehavior.IMMUTABLE) public class ResponseMissingRequestIdInterceptor implements HttpResponseInterceptor { - @Override - public void process(final HttpResponse response, final HttpContext context) throws HttpException, IOException { - + public void process(final HttpResponse response, final EntityDetails entity, final HttpContext context) throws HttpException, IOException { if (response.getFirstHeader(GDC_REQUEST_ID) == null) { - final HttpCoreContext coreContext = HttpCoreContext.adapt(context); - final Header requestIdHeader = coreContext.getRequest().getFirstHeader(GDC_REQUEST_ID); - response.setHeader(GDC_REQUEST_ID, requestIdHeader.getValue()); + HttpCoreContext coreContext = HttpCoreContext.cast(context); + HttpRequest request = coreContext.getRequest(); // Modern, non-deprecated + if (request != null) { + Header requestIdHeader = request.getFirstHeader(GDC_REQUEST_ID); + if (requestIdHeader != null) { + response.setHeader(GDC_REQUEST_ID, requestIdHeader.getValue()); + } + } } } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/account/AccountService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/account/AccountService.java index 68b1a13f1..f820b6966 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/account/AccountService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/account/AccountService.java @@ -6,7 +6,6 @@ package com.gooddata.sdk.service.account; import com.gooddata.sdk.common.GoodDataException; -import com.gooddata.sdk.common.GoodDataRestException; import com.gooddata.sdk.model.account.Account; import com.gooddata.sdk.model.account.Accounts; import com.gooddata.sdk.model.account.SeparatorSettings; @@ -14,34 +13,29 @@ import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; -import org.springframework.http.HttpStatus; -import org.springframework.http.converter.json.MappingJacksonValue; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriTemplate; import static com.gooddata.sdk.common.util.Validate.notEmpty; import static com.gooddata.sdk.common.util.Validate.notNull; import static com.gooddata.sdk.common.util.Validate.notNullState; + /** * Service to access and manipulate account. */ public class AccountService extends AbstractService { + public static final UriTemplate ACCOUNT_TEMPLATE = new UriTemplate(Account.URI); public static final UriTemplate ACCOUNTS_TEMPLATE = new UriTemplate(Account.ACCOUNTS_URI); public static final UriTemplate ACCOUNT_BY_LOGIN_TEMPLATE = new UriTemplate(Account.ACCOUNT_BY_EMAIL_URI); public static final UriTemplate LOGIN_TEMPLATE = new UriTemplate(Account.LOGIN_URI); public static final UriTemplate SEPARATORS_TEMPLATE = new UriTemplate(SeparatorSettings.URI); - /** - * Constructs service for GoodData account management. - * @param restTemplate RESTful HTTP Spring template - * @param settings settings - */ - public AccountService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + + public AccountService(WebClient webClient, GoodDataSettings settings) { + super(webClient, settings); } /** @@ -62,12 +56,17 @@ public Account getCurrent() { public void logout() { try { final String id = getCurrent().getId(); - restTemplate.delete(Account.LOGIN_URI, id); - } catch (GoodDataException | RestClientException e) { + webClient.delete() + .uri(Account.LOGIN_URI, id) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to logout", e); } } + /** * Creates new account in given organization (domain). * Only domain admin is allowed create new accounts! This means rest request has to authorized as domain admin. @@ -81,9 +80,16 @@ public Account createAccount(Account account, String organizationName) { notEmpty(organizationName, "organizationName"); try { - final UriResponse uriResponse = restTemplate.postForObject(Account.ACCOUNTS_URI, account, UriResponse.class, organizationName); + UriResponse uriResponse = webClient.post() + .uri(uriBuilder -> uriBuilder + .path(Account.ACCOUNTS_URI) + .build(organizationName)) + .bodyValue(account) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); return getAccountByUri(notNullState(uriResponse, "created account response").getUri()); - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to create account", e); } } @@ -99,40 +105,32 @@ public void removeAccount(final Account account) { notNull(account.getUri(), "account.uri"); try { - restTemplate.delete(account.getUri()); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { - throw new AccountNotFoundException(account.getUri(), e); - } else { - throw e; - } - } catch (GoodDataException e) { + webClient.delete() + .uri(account.getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to remove account", e); } } - /** - * Get account for given account id - * @param id to search for - * @return account for id - * @throws AccountNotFoundException when account for given id can't be found - * @throws GoodDataException when different error occurs - */ public Account getAccountById(final String id) { notNull(id, "id"); try { - return restTemplate.getForObject(Account.URI, Account.class, id); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { - throw new AccountNotFoundException(ACCOUNT_TEMPLATE.expand(id).toString(), e); - } else { - throw e; - } - } catch (RestClientException e) { + return webClient.get() + .uri(uriBuilder -> uriBuilder + .path(Account.URI) + .build(id)) + .retrieve() + .bodyToMono(Account.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to get account", e); } } + /** * Get account by given login. * Only domain admin is allowed to search users by login. @@ -146,14 +144,19 @@ public Account getAccountByLogin(final String email, final String organizationNa notNull(email, "email"); notNull(organizationName, "organizationName"); try { - final Accounts accounts = restTemplate.getForObject( - Account.ACCOUNT_BY_EMAIL_URI, Accounts.class, organizationName, email); + Accounts accounts = webClient.get() + .uri(uriBuilder -> uriBuilder + .path(Account.ACCOUNT_BY_EMAIL_URI) + .build(organizationName, email)) + .retrieve() + .bodyToMono(Accounts.class) + .block(); if (accounts != null && !accounts.getPageItems().isEmpty()) { return accounts.getPageItems().get(0); } throw new AccountNotFoundException("User was not found by email " + - email + " in organization " + organizationName, Account.ACCOUNT_BY_EMAIL_URI); - } catch (RestClientException e) { + email + " in organization " + organizationName, Account.ACCOUNT_BY_EMAIL_URI); + } catch (Exception e) { throw new GoodDataException("Unable to get account", e); } } @@ -180,16 +183,14 @@ public void updateAccount(final Account account) { notNull(account.getUri(), "account.uri"); try { - final MappingJacksonValue jacksonValue = new MappingJacksonValue(account); - jacksonValue.setSerializationView(Account.UpdateView.class); - restTemplate.put(account.getUri(), jacksonValue); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { - throw new AccountNotFoundException(account.getUri(), e); - } else { - throw e; - } - } catch (GoodDataException e) { + // Changed: .put() with WebClient; manual JSON view can be used if needed + webClient.put() + .uri(account.getUri()) + .bodyValue(account) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to update account", e); } } @@ -205,8 +206,12 @@ public SeparatorSettings getSeparatorSettings(final Account account) { notEmpty(account.getUri(), "account.uri"); try { - return restTemplate.getForObject(SEPARATORS_TEMPLATE.expand(account.getId()), SeparatorSettings.class); - } catch (RestClientException e) { + return webClient.get() + .uri(SEPARATORS_TEMPLATE.expand(account.getId())) + .retrieve() + .bodyToMono(SeparatorSettings.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to get separators for account=" + account.getUri(), e); } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/AuditEventService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/AuditEventService.java index 336748b1c..4a0fed8be 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/AuditEventService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/AuditEventService.java @@ -6,7 +6,6 @@ package com.gooddata.sdk.service.auditevent; import com.gooddata.sdk.common.GoodDataException; -import com.gooddata.sdk.common.GoodDataRestException; import com.gooddata.sdk.common.collections.PageBrowser; import com.gooddata.sdk.common.collections.PageRequest; import com.gooddata.sdk.common.util.SpringMutableUri; @@ -16,13 +15,14 @@ import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; import com.gooddata.sdk.service.account.AccountService; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; + +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; import org.springframework.web.util.UriTemplate; import static com.gooddata.sdk.common.util.Validate.notEmpty; import static com.gooddata.sdk.common.util.Validate.notNull; -import static org.springframework.http.HttpStatus.UNAUTHORIZED; +import org.springframework.http.HttpStatus; /** * List audit events. @@ -36,12 +36,12 @@ public class AuditEventService extends AbstractService { /** * Service for audit events - * @param restTemplate rest template + * @param webClient web client * @param accountService account service * @param settings settings */ - public AuditEventService(final RestTemplate restTemplate, final AccountService accountService, final GoodDataSettings settings) { - super(restTemplate, settings); + public AuditEventService(final WebClient webClient, final AccountService accountService, final GoodDataSettings settings) { + super(webClient, settings); this.accountService = notNull(accountService, "account service"); } @@ -122,18 +122,22 @@ public PageBrowser listAuditEvents(final PageRequest page) { } private AuditEvents doListAuditEvents(final String uri) { - try { - return restTemplate.getForObject(uri, AuditEvents.class); - } catch (GoodDataRestException e) { - if (UNAUTHORIZED.value() == e.getStatusCode()) { - throw new AuditEventsForbiddenException(e); - } else { - throw e; + try { + return webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(AuditEvents.class) + .block(); + } catch (WebClientResponseException e) { + if (HttpStatus.UNAUTHORIZED.equals(e.getStatusCode())) { + throw new AuditEventsForbiddenException(e); + } else { + throw e; + } + } catch (Exception e) { + throw new GoodDataException("Unable to list audit events: " + uri, e); } - } catch (RestClientException e) { - throw new GoodDataException("Unable to list audit events: " + uri); } - } private String getAuditEventsUri(final PageRequest page, final String uri) { return page.updateWithPageParams(new SpringMutableUri(uri)).toUriString(); diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/connector/ConnectorService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/connector/ConnectorService.java index c6f58352b..5f8ef0645 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/connector/ConnectorService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/connector/ConnectorService.java @@ -13,13 +13,15 @@ import com.gooddata.sdk.model.project.ProjectTemplate; import com.gooddata.sdk.service.*; import com.gooddata.sdk.service.project.ProjectService; -import org.springframework.http.HttpStatus; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import com.gooddata.sdk.service.retry.RetryableWebClient; +import com.gooddata.sdk.service.retry.GetServerErrorRetryStrategy; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.util.UriTemplate; -import java.io.IOException; +import org.springframework.http.HttpMethod; +import java.net.URI; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -35,10 +37,12 @@ public class ConnectorService extends AbstractService { public static final UriTemplate STATUS_TEMPLATE = new UriTemplate(IntegrationProcessStatus.URI); private final ProjectService projectService; + private final RetryableWebClient retryableWebClient; - public ConnectorService(final RestTemplate restTemplate, final ProjectService projectService, final GoodDataSettings settings) { - super(restTemplate, settings); + public ConnectorService(final WebClient webClient, final ProjectService projectService, final GoodDataSettings settings) { + super(webClient, settings); this.projectService = notNull(projectService, "projectService"); + this.retryableWebClient = new RetryableWebClient(webClient, settings.getRetrySettings(), new GetServerErrorRetryStrategy()); } /** @@ -55,14 +59,47 @@ public Integration getIntegration(final Project project, final ConnectorType con notNull(connectorType, "connector"); try { - return restTemplate.getForObject(Integration.URL, Integration.class, project.getId(), connectorType.getName()); + String url = Integration.URL.replace("{project}", project.getId()) + .replace("{connector}", connectorType.getName()); + + // For retryable client, we need to construct the full URI + // Since the retryable client's execute method expects a complete URI, + // we'll need to use a different approach for now to maintain compatibility + // Let's use the webClient directly but check if we need retries based on response + return webClient.get() + .uri(url) + .retrieve() + .bodyToMono(Integration.class) + .retryWhen(reactor.util.retry.Retry.backoff( + settings.getRetrySettings().getRetryCount(), + java.time.Duration.ofMillis(settings.getRetrySettings().getRetryInitialInterval())) + .maxBackoff(java.time.Duration.ofMillis(settings.getRetrySettings().getRetryMaxInterval())) + .filter(throwable -> { + if (throwable instanceof WebClientResponseException) { + WebClientResponseException wcre = (WebClientResponseException) throwable; + // Only retry for GET operations with server errors (500, 502, 503, 504, 507) + return new GetServerErrorRetryStrategy().retryAllowed("GET", wcre.getStatusCode().value(), null); + } + return false; + })) + .onErrorMap(WebClientResponseException.class, e -> { + if (e.getStatusCode().value() == 404) { + return new IntegrationNotFoundException(project, connectorType, e); + } else { + return new GoodDataRestException( + e.getStatusCode().value(), + e.getStatusText(), + e.getResponseBodyAsString(), + url, + "WebClient" + ); + } + }) + .block(); } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { - throw new IntegrationNotFoundException(project, connectorType, e); - } else { - throw e; - } - } catch (RestClientException e) { + // Re-throw GoodDataRestException (including IntegrationNotFoundException) as-is + throw e; + } catch (Exception e) { throw new ConnectorException("Unable to get " + connectorType + " integration", e); } } @@ -108,9 +145,15 @@ public Integration createIntegration(final Project project, final ConnectorType notNull(integration, "integration"); try { - return restTemplate.postForObject(Integration.URL, integration, Integration.class, project.getId(), - connectorType.getName()); - } catch (GoodDataRestException | RestClientException e) { + String url = Integration.URL.replace("{project}", project.getId()) + .replace("{connector}", connectorType.getName()); + return webClient.post() + .uri(url) + .bodyValue(integration) + .retrieve() + .bodyToMono(Integration.class) + .block(); + } catch (Exception e) { throw new ConnectorException("Unable to create " + connectorType + " integration", e); } } @@ -131,14 +174,29 @@ public void updateIntegration(final Project project, final ConnectorType connect notNull(integration, "integration"); try { - restTemplate.put(Integration.URL, integration, project.getId(), connectorType.getName()); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { + String url = Integration.URL.replace("{project}", project.getId()) + .replace("{connector}", connectorType.getName()); + webClient.put() + .uri(url) + .bodyValue(integration) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException e) { + if (e.getStatusCode().value() == 404) { throw new IntegrationNotFoundException(project, connectorType, e); } else { - throw e; + String url = Integration.URL.replace("{project}", project.getId()) + .replace("{connector}", connectorType.getName()); + throw new GoodDataRestException( + e.getStatusCode().value(), + e.getStatusText(), + e.getResponseBodyAsString(), + url, + "WebClient" + ); } - } catch (RestClientException e) { + } catch (Exception e) { throw new ConnectorException("Unable to update " + connectorType + " integration", e); } } @@ -155,16 +213,30 @@ public void deleteIntegration(final Project project, final ConnectorType connect notNull(project, "project"); notNull(project.getId(), "project.id"); notNull(connectorType, "connector"); - + try { - restTemplate.delete(Integration.URL, project.getId(), connectorType.getName()); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { + String url = Integration.URL.replace("{project}", project.getId()) + .replace("{connector}", connectorType.getName()); + webClient.delete() + .uri(url) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException e) { + if (e.getStatusCode().value() == 404) { throw new IntegrationNotFoundException(project, connectorType, e); } else { - throw e; + String url = Integration.URL.replace("{project}", project.getId()) + .replace("{connector}", connectorType.getName()); + throw new GoodDataRestException( + e.getStatusCode().value(), + e.getStatusText(), + e.getResponseBodyAsString(), + url, + "WebClient" + ); } - } catch (RestClientException e) { + } catch (Exception e) { throw new ConnectorException("Unable to delete " + connectorType + " integration", e); } } @@ -195,8 +267,13 @@ public T getSettings(final Project project, final Connector notNull(settingsClass, "settingsClass"); try { - return restTemplate.getForObject(connectorType.getSettingsUrl(), settingsClass, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + String url = connectorType.getSettingsUrl().replace("{project}", project.getId()); + return webClient.get() + .uri(url) + .retrieve() + .bodyToMono(settingsClass) + .block(); + } catch (Exception e) { throw new ConnectorException("Unable to get " + connectorType + " integration settings", e); } } @@ -215,8 +292,14 @@ public void updateSettings(final Project project, final Settings settings) { notNull(project, "project"); try { - restTemplate.put(settings.getConnectorType().getSettingsUrl(), settings, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + String url = settings.getConnectorType().getSettingsUrl().replace("{project}", project.getId()); + webClient.put() + .uri(url) + .bodyValue(settings) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { throw new ConnectorException("Unable to set " + settings.getConnectorType() + " settings", e); } } @@ -236,10 +319,16 @@ public FutureResult executeProcess(final Project project, final P final String connectorType = execution.getConnectorType().getName(); try { - final UriResponse response = restTemplate - .postForObject(ProcessStatus.URL, execution, UriResponse.class, project.getId(), connectorType); + String url = ProcessStatus.URL.replace("{project}", project.getId()) + .replace("{connector}", connectorType); + final UriResponse response = webClient.post() + .uri(url) + .bodyValue(execution) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); return createProcessPollResult(notNullState(response, "created process response").getUri()); - } catch (GoodDataRestException | RestClientException e) { + } catch (Exception e) { throw new ConnectorException("Unable to execute " + connectorType + " process", e); } } @@ -281,28 +370,48 @@ public Reload getZendesk4Reload(final Reload reload) { } /** - * Get Zendesk reload. + * Get Zendesk reload by URI using WebClient. * @param reloadUri existing reload URI * @return reload */ public Reload getZendesk4ReloadByUri(final String reloadUri) { notNull(reloadUri, "reloadUri"); try { - return restTemplate.getForObject(reloadUri, Reload.class); - } catch (GoodDataRestException | RestClientException e) { + return webClient.get() + .uri(reloadUri) + .retrieve() + .bodyToMono(Reload.class) + .block(); + } catch (Exception e) { throw new ConnectorException("Unable to get reload", e); } } - /** - * Scheduler new reload. - * @param project project to reload - * @param reload reload parameters - * @return created reload - */ - public Reload scheduleZendesk4Reload(final Project project, final Reload reload) { - return restTemplate.postForObject(Reload.URL, reload, Reload.class, project.getId()); - } + + /** + * Schedule a new Zendesk4 reload using WebClient. + * @param project project to reload + * @param reload reload parameters + * @return created reload + */ + public Reload scheduleZendesk4Reload(final Project project, final Reload reload) { + notNull(project, "project"); + notNull(project.getId(), "project.id"); + notNull(reload, "reload"); + + try { + String url = Reload.URL.replace("{project}", project.getId()); // если в шаблоне есть {projectId} + return webClient.post() + .uri(url) + .bodyValue(reload) + .retrieve() + .bodyToMono(Reload.class) + .block(); + } catch (Exception e) { + throw new ConnectorException("Unable to schedule Zendesk4 reload for project " + project.getId(), e); + } + } + protected FutureResult createProcessPollResult(final String uri) { final Map match = STATUS_TEMPLATE.match(uri); @@ -310,9 +419,15 @@ protected FutureResult createProcessPollResult(final String uri) final String processId = match.get("process"); return new PollResult<>(this, new SimplePollHandler(uri, ProcessStatus.class) { @Override - public boolean isFinished(final ClientHttpResponse response) throws IOException { - final ProcessStatus process = extractData(response, ProcessStatus.class); - return process.isFinished(); + public boolean isFinished(final ClientResponse response) { + int code = response.statusCode().value(); + if (code == 200) { + ProcessStatus process = response.bodyToMono(ProcessStatus.class).block(); + return process != null && process.isFinished(); + } else if (code == 202) { + return false; + } + throw new ConnectorException(format("%s process %s returned unknown HTTP code %s", connectorType, processId, code)); } @Override diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/dataload/OutputStageService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/dataload/OutputStageService.java index 85f0ca7fb..ebfb93de4 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/dataload/OutputStageService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/dataload/OutputStageService.java @@ -6,17 +6,11 @@ package com.gooddata.sdk.service.dataload; import com.gooddata.sdk.common.GoodDataException; -import com.gooddata.sdk.common.GoodDataRestException; import com.gooddata.sdk.model.dataload.OutputStage; import com.gooddata.sdk.model.project.Project; import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; -import com.gooddata.sdk.service.dataload.processes.ProcessNotFoundException; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriTemplate; import static com.gooddata.sdk.common.util.Validate.*; @@ -29,36 +23,44 @@ public class OutputStageService extends AbstractService { public static final UriTemplate OUTPUT_STAGE_TEMPLATE = new UriTemplate(OutputStage.URI); /** - * Sets RESTful HTTP Spring template. Should be called from constructor of concrete service extending - * this abstract one. - * @param restTemplate RESTful HTTP Spring template - * @param settings settings + * Constructor accepting WebClient and settings. + * @param webClient WebClient for HTTP communication + * @param settings configuration settings */ - public OutputStageService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public OutputStageService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** - * Get output stage by given URI. - * @param uri output stage uri + * Get output stage by a given URI. + * @param uri output stage URI * @return output stage object - * @throws ProcessNotFoundException when the process doesn't exist + * @throws GoodDataException if the output stage does not exist or an error occurs */ public OutputStage getOutputStageByUri(final String uri) { notEmpty(uri, "uri"); isTrue(OUTPUT_STAGE_TEMPLATE.matches(uri), "uri does not match output stage pattern: " + OUTPUT_STAGE_TEMPLATE.toString()); try { - return restTemplate.getForObject(uri, OutputStage.class); - } catch (RestClientException e) { + OutputStage outputStage = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(OutputStage.class) + .block(); + + if (outputStage == null) { + throw new GoodDataException("OutputStage not found: " + uri); + } + return outputStage; + } catch (Exception e) { throw new GoodDataException("Unable to get output stage " + uri, e); } } /** - * Get output stage by given project. - * @param project project to which the process belongs - * @return output stage - * @throws ProcessNotFoundException when the process doesn't exist + * Get output stage by project. + * @param project project for which to get the output stage + * @return output stage object + * @throws GoodDataException if the output stage does not exist or an error occurs */ public OutputStage getOutputStage(final Project project) { notNull(project, "project"); @@ -68,24 +70,29 @@ public OutputStage getOutputStage(final Project project) { } /** - * Update output stage. - * - * @param outputStage output stage + * Update the output stage. + * @param outputStage output stage to update * @return updated output stage + * @throws GoodDataException if update fails or the response is empty */ public OutputStage updateOutputStage(final OutputStage outputStage) { notNull(outputStage, "outputStage"); notNull(outputStage.getUri(), "outputStage.uri"); try { - HttpEntity outputStageHttpEntity = new HttpEntity<>(outputStage); - ResponseEntity response = restTemplate.exchange(outputStage.getUri(), HttpMethod.PUT, outputStageHttpEntity, OutputStage.class); - if (response.getBody() == null) { - throw new RestClientException("unexpected response body"); + OutputStage updated = webClient.put() + .uri(outputStage.getUri()) + .bodyValue(outputStage) + .retrieve() + .bodyToMono(OutputStage.class) + .block(); + + if (updated == null) { + throw new GoodDataException("Unexpected empty response body"); } - return response.getBody(); - } catch (GoodDataRestException | RestClientException e) { - throw new GoodDataException("Unable to update output stage, uri: " + outputStage.getUri()); + return updated; + } catch (Exception e) { + throw new GoodDataException("Unable to update output stage, uri: " + outputStage.getUri(), e); } } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/dataload/processes/ProcessService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/dataload/processes/ProcessService.java index 9f83616af..0a045dfa9 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/dataload/processes/ProcessService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/dataload/processes/ProcessService.java @@ -5,6 +5,7 @@ */ package com.gooddata.sdk.service.dataload.processes; +import com.fasterxml.jackson.databind.ObjectMapper; import com.gooddata.sdk.common.GoodDataException; import com.gooddata.sdk.common.GoodDataRestException; import com.gooddata.sdk.common.collections.CustomPageRequest; @@ -41,10 +42,14 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.MultipartBodyBuilder; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; import org.springframework.web.util.UriTemplate; import java.io.File; @@ -61,11 +66,17 @@ import static java.util.Collections.emptyList; import static org.apache.commons.lang3.Validate.isTrue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + /** * Service to manage dataload processes and process executions. */ public class ProcessService extends AbstractService { + private static final Logger log = LoggerFactory.getLogger(ProcessService.class); + public static final UriTemplate SCHEDULE_TEMPLATE = new UriTemplate(Schedule.URI); public static final UriTemplate PROCESS_TEMPLATE = new UriTemplate(DataloadProcess.URI); public static final UriTemplate SCHEDULES_TEMPLATE = new UriTemplate(Schedules.URI); @@ -87,9 +98,9 @@ public class ProcessService extends AbstractService { * @param dataStoreService service for upload process data * @param settings settings */ - public ProcessService(final RestTemplate restTemplate, final AccountService accountService, + public ProcessService(final WebClient webClient, final AccountService accountService, final DataStoreService dataStoreService, final GoodDataSettings settings) { - super(restTemplate, settings); + super(webClient, settings); this.dataStoreService = dataStoreService; this.accountService = notNull(accountService, "accountService"); } @@ -183,18 +194,31 @@ public FutureResult updateProcessFromAppstore(DataloadProcess p public DataloadProcess getProcessByUri(String uri) { notEmpty(uri, "uri"); try { - return restTemplate.getForObject(uri, DataloadProcess.class); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { + return webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(DataloadProcess.class) + .block(); + } catch (WebClientResponseException e) { + if (e.getStatusCode().value() == HttpStatus.NOT_FOUND.value()) { throw new ProcessNotFoundException(uri, e); } else { throw e; } - } catch (RestClientException e) { + } catch (GoodDataRestException e) { + // Map 404 GoodDataRestException to ProcessNotFoundException + if (e.getStatusCode() == 404) { + throw new ProcessNotFoundException(uri, e); + } else { + throw new GoodDataException("Unable to get process " + uri, e); + } + } catch (Exception e) { throw new GoodDataException("Unable to get process " + uri, e); } } + + /** * Get process by given id and project. * @param project project to which the process belongs @@ -233,8 +257,12 @@ public Collection listUserProcesses() { public void removeProcess(DataloadProcess process) { notNull(process, "process"); try { - restTemplate.delete(process.getUri()); - } catch (GoodDataException | RestClientException e) { + webClient.delete() + .uri(process.getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException | GoodDataException e) { throw new GoodDataException("Unable to remove process " + process.getUri(), e); } } @@ -249,9 +277,15 @@ public void getProcessSource(DataloadProcess process, OutputStream outputStream) notNull(process, "process"); notNull(outputStream, "outputStream"); try { - restTemplate.execute(process.getSourceUri(), HttpMethod.GET, - null, new OutputStreamResponseExtractor(outputStream)); - } catch (GoodDataException | RestClientException e) { + byte[] bytes = webClient.get() + .uri(process.getSourceUri()) + .retrieve() + .bodyToMono(byte[].class) + .block(); + if (bytes != null) { + outputStream.write(bytes); + } + } catch (WebClientResponseException | IOException e) { throw new GoodDataException("Unable to get process source " + process.getSourceUri(), e); } } @@ -265,9 +299,15 @@ public void getExecutionLog(ProcessExecutionDetail executionDetail, OutputStream notNull(executionDetail, "executionDetail"); notNull(outputStream, "outputStream"); try { - restTemplate.execute(executionDetail.getLogUri(), HttpMethod.GET, - null, new OutputStreamResponseExtractor(outputStream)); - } catch (GoodDataException | RestClientException e) { + byte[] bytes = webClient.get() + .uri(executionDetail.getLogUri()) + .retrieve() + .bodyToMono(byte[].class) + .block(); + if (bytes != null) { + outputStream.write(bytes); + } + } catch (WebClientResponseException | IOException e) { throw new GoodDataException("Unable to get process execution log " + executionDetail.getLogUri(), e); } } @@ -283,8 +323,13 @@ public FutureResult executeProcess(ProcessExecution exec notNull(execution, "execution"); ProcessExecutionTask executionTask; try { - executionTask = restTemplate.postForObject(execution.getExecutionsUri(), execution, ProcessExecutionTask.class); - } catch (GoodDataException | RestClientException e) { + executionTask = webClient.post() + .uri(execution.getExecutionsUri()) + .bodyValue(execution) + .retrieve() + .bodyToMono(ProcessExecutionTask.class) + .block(); + } catch (WebClientResponseException | GoodDataException e) { throw new ProcessExecutionException("Cannot execute process", e); } @@ -296,8 +341,8 @@ public FutureResult executeProcess(ProcessExecution exec return new PollResult<>(this, new AbstractPollHandler(executionTask.getPollUri(), Void.class, ProcessExecutionDetail.class) { @Override - public boolean isFinished(ClientHttpResponse response) throws IOException { - return HttpStatus.NO_CONTENT.equals(response.getStatusCode()); + public boolean isFinished(ClientResponse response) { + return response.statusCode().equals(HttpStatus.NO_CONTENT); } @Override @@ -321,8 +366,12 @@ public void handlePollException(final GoodDataRestException e) { private ProcessExecutionDetail getProcessExecutionDetailByUri(final String uri) { try { - return restTemplate.getForObject(uri, ProcessExecutionDetail.class); - } catch (GoodDataException | RestClientException e) { + return webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(ProcessExecutionDetail.class) + .block(); + } catch (WebClientResponseException | GoodDataException e) { throw new ProcessExecutionException("Execution finished, but cannot get its result.", e, uri); } } @@ -357,21 +406,21 @@ public Schedule updateSchedule(Schedule schedule) { final String uri = schedule.getUri(); try { - final ResponseEntity response = restTemplate - .exchange(uri, HttpMethod.PUT, new HttpEntity<>(schedule), Schedule.class); - if (response == null) { - throw new GoodDataException("Unable to update schedule. No response returned from API."); - } - return response.getBody(); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { - throw new ScheduleNotFoundException(uri, e); - } else { - throw e; + return webClient.put() + .uri(uri) + .bodyValue(schedule) + .retrieve() + .bodyToMono(Schedule.class) + .block(); + } catch (WebClientResponseException e) { + if (e.getStatusCode().value() == HttpStatus.NOT_FOUND.value()) { + throw new ScheduleNotFoundException(uri, e); + } else { + throw e; + } + } catch (Exception e) { + throw new GoodDataException("Unable to get schedule " + uri, e); } - } catch (RestClientException e) { - throw new GoodDataException("Unable to get schedule " + uri, e); - } } /** @@ -384,14 +433,18 @@ public Schedule updateSchedule(Schedule schedule) { public Schedule getScheduleByUri(String uri) { notEmpty(uri, "uri"); try { - return restTemplate.getForObject(uri, Schedule.class); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { + return webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(Schedule.class) + .block(); + } catch (WebClientResponseException e) { + if (e.getStatusCode().value() == HttpStatus.NOT_FOUND.value()) { throw new ScheduleNotFoundException(uri, e); } else { throw e; } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get schedule " + uri, e); } } @@ -444,8 +497,12 @@ public void removeSchedule(final Schedule schedule) { notNull(schedule.getUri(), "schedule.uri"); try { - restTemplate.delete(schedule.getUri()); - } catch (GoodDataException | RestClientException e) { + webClient.delete() + .uri(schedule.getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException | GoodDataException e) { throw new GoodDataException("Unable to remove schedule " + schedule.getUri(), e); } } @@ -462,8 +519,13 @@ public FutureResult executeSchedule(final Schedule schedule) ScheduleExecution scheduleExecution; try { - scheduleExecution = restTemplate.postForObject(schedule.getExecutionsUri(), new ScheduleExecution(), ScheduleExecution.class); - } catch (GoodDataException | RestClientException e) { + scheduleExecution = webClient.post() + .uri(schedule.getExecutionsUri()) + .bodyValue(new ScheduleExecution()) + .retrieve() + .bodyToMono(ScheduleExecution.class) + .block(); + } catch (RuntimeException e) { throw new ScheduleExecutionException("Cannot execute schedule", e); } @@ -471,8 +533,8 @@ public FutureResult executeSchedule(final Schedule schedule) notNullState(scheduleExecution, "created schedule execution").getUri(), ScheduleExecution.class, ScheduleExecution.class) { @Override - public boolean isFinished(ClientHttpResponse response) throws IOException { - final ScheduleExecution pollResult = extractData(response, ScheduleExecution.class); + public boolean isFinished(ClientResponse response) { + final ScheduleExecution pollResult = extractData(response, ScheduleExecution.class); return pollResult.isFinished(); } @@ -490,12 +552,16 @@ public void handlePollException(final GoodDataRestException e) { private Page listSchedules(URI uri) { try { - final Schedules schedules = restTemplate.getForObject(uri, Schedules.class); + final Schedules schedules = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(Schedules.class) + .block(); if (schedules == null) { return new Page<>(); } return schedules; - } catch (GoodDataException | RestClientException e) { + } catch (WebClientResponseException | GoodDataException e) { throw new GoodDataException("Unable to list schedules", e); } } @@ -520,25 +586,35 @@ private static URI getSchedulesUri(final Project project, final PageRequest page private Schedule postSchedule(Schedule schedule, URI postUri) { try { - return restTemplate.postForObject(postUri, schedule, Schedule.class); - } catch (GoodDataException | RestClientException e) { + return webClient.post() + .uri(postUri) + .bodyValue(schedule) + .retrieve() + .bodyToMono(Schedule.class) + .block(); + } catch (WebClientResponseException | GoodDataException e) { throw new GoodDataException("Unable to post schedule.", e); } } private Collection listProcesses(URI uri) { try { - final DataloadProcesses processes = restTemplate.getForObject(uri, DataloadProcesses.class); + final DataloadProcesses processes = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(DataloadProcesses.class) + .block(); if (processes == null) { throw new GoodDataException("empty response from API call"); } else if (processes.getItems() == null) { return emptyList(); } return processes.getItems(); - } catch (GoodDataException | RestClientException e) { + } catch (RuntimeException e) { + // Wrap any unexpected error in GoodDataException throw new GoodDataException("Unable to list processes", e); } - } + } private static URI getProcessUri(Project project, String id) { notNull(project, "project"); @@ -552,6 +628,7 @@ private static URI getProcessesUri(Project project) { return PROCESSES_TEMPLATE.expand(project.getId()); } + private DataloadProcess postProcess(DataloadProcess process, File processData, URI postUri) { File tempFile = createTempFile("process", ".zip"); @@ -561,82 +638,123 @@ private DataloadProcess postProcess(DataloadProcess process, File processData, U throw new GoodDataException("Unable to zip process data", e); } - Object processToSend; - HttpMethod method = HttpMethod.POST; - if (dataStoreService != null && tempFile.length() > MAX_MULTIPART_SIZE) { - try (final InputStream input = Files.newInputStream(tempFile.toPath())) { - process.setPath(dataStoreService.getUri(tempFile.getName()).getPath()); - dataStoreService.upload(tempFile.getName(), input); - processToSend = process; - if (PROCESS_TEMPLATE.matches(postUri.toString())) { - method = HttpMethod.PUT; + try { + if (dataStoreService != null && tempFile.length() > MAX_MULTIPART_SIZE) { + try (final InputStream input = Files.newInputStream(tempFile.toPath())) { + process.setPath(dataStoreService.getUri(tempFile.getName()).getPath()); + dataStoreService.upload(tempFile.getName(), input); + + // Log process details before sending + log.debug("Process details: {}", process); + + // Check for null before sending the process object + if (process == null) { + throw new IllegalArgumentException("Request body for process POST must not be null"); + } + + DataloadProcess result = webClient.post() + .uri(postUri) + .bodyValue(process) + .retrieve() + .bodyToMono(DataloadProcess.class) + .block(); + if (result == null) { + throw new GoodDataException("No response from API (null result) when posting dataload process (large, via WebDAV)."); + } + return result; + } catch (IOException e) { + throw new GoodDataException("Unable to access zipped process data at " + tempFile.getAbsolutePath(), e); } - } catch (IOException e) { - throw new GoodDataException("Unable to access zipped process data at " - + tempFile.getAbsolutePath(), e); - } - } else { - if (dataStoreService == null) { // we have no WebDAV support, so let's try send big file by multipart - if (logger.isInfoEnabled()) { - logger.info("WebDAV calls not supported - sending huge file using multipart. " + - "Consider adding com.github.lookfirst:sardine to dependencies."); + } else { + MultipartBodyBuilder builder = new MultipartBodyBuilder(); + builder.part("process", process); + builder.part("data", new FileSystemResource(tempFile)) + .header(HttpHeaders.CONTENT_TYPE, MEDIA_TYPE_ZIP.toString()); + + // Log process details before sending multipart request + log.debug("Process details: {}", process); + + DataloadProcess result = webClient.post() + .uri(postUri) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(builder.build())) + .retrieve() + .bodyToMono(DataloadProcess.class) + .block(); + if (result == null) { + throw new GoodDataException("No response from API (null result) when posting dataload process (multipart)."); } + return result; } - final MultiValueMap parts = new LinkedMultiValueMap<>(2); - parts.add("process", process); - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MEDIA_TYPE_ZIP); - parts.add("data", new HttpEntity<>(new FileSystemResource(tempFile), headers)); - processToSend = parts; - } - - try { - final ResponseEntity response = restTemplate - .exchange(postUri, method, new HttpEntity<>(processToSend), DataloadProcess.class); - if (response == null) { - throw new GoodDataException("Unable to post dataload process. No response returned from API."); - } - return response.getBody(); - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to post dataload process.", e); } finally { deleteTempFile(tempFile); } } + + + private FutureResult postProcess(DataloadProcess process, URI postUri, HttpMethod method) { try { - ResponseEntity exchange = restTemplate.exchange(postUri, method, new HttpEntity<>(process), String.class); - if (exchange.getStatusCode() == HttpStatus.ACCEPTED) { //deployment worker will create process - AsyncTask asyncTask = mapper.readValue(exchange.getBody(), AsyncTask.class); - return new PollResult<>(this, new SimplePollHandler(asyncTask.getUri(), DataloadProcess.class) { + ClientResponse response; + if (method == HttpMethod.POST) { + response = webClient.post() + .uri(postUri) + .bodyValue(process) + .exchange() + .block(); + } else if (method == HttpMethod.PUT) { + response = webClient.put() + .uri(postUri) + .bodyValue(process) + .exchange() + .block(); + } else { + throw new IllegalStateException("Unsupported HTTP method: " + method); + } + if (response == null) { + throw new GoodDataException("No response received from API call"); + } + + ObjectMapper mapper = new ObjectMapper(); + String body = response.bodyToMono(String.class).block(); + + if (response.statusCode().equals(HttpStatus.ACCEPTED)) { + AsyncTask asyncTask = mapper.readValue(body, AsyncTask.class); + return new PollResult<>(this, new SimplePollHandler(asyncTask.getUri(), DataloadProcess.class) { @Override public void handlePollException(GoodDataRestException e) { throw new GoodDataException("Creating process failed", e); } }); - } else if (exchange.getStatusCode() == HttpStatus.OK) { //object has been found in package registry, deployment worker is not triggered - final DataloadProcess dataloadProcess = mapper.readValue(exchange.getBody(), DataloadProcess.class); + } else if (response.statusCode().equals(HttpStatus.OK)) { + final DataloadProcess dataloadProcess = mapper.readValue(body, DataloadProcess.class); return new PollResult<>(this, new SimplePollHandler(dataloadProcess.getUri(), DataloadProcess.class) { - @Override public void handlePollException(GoodDataRestException e) { throw new GoodDataException("Creating process failed", e); } }); } else { - throw new IllegalStateException("Unexpected status code from resource: " + exchange.getStatusCode()); + throw new IllegalStateException("Unexpected status code from resource: " + response.statusCode()); } - } catch (RestClientException | IOException e) { + } catch (WebClientResponseException | IOException e) { throw new GoodDataException("Creating process failed", e); } } private DataloadProcess postProcess(DataloadProcess process, URI postUri) { try { - return restTemplate.postForObject(postUri, process, DataloadProcess.class); - } catch (GoodDataException | RestClientException e) { + return webClient.post() + .uri(postUri) + .bodyValue(process) + .retrieve() + .bodyToMono(DataloadProcess.class) + .block(); + } catch (WebClientResponseException | GoodDataException e) { throw new GoodDataException("Unable to create dataload process.", e); } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/dataset/DatasetService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/dataset/DatasetService.java index c21536dc1..ca4378586 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/dataset/DatasetService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/dataset/DatasetService.java @@ -15,33 +15,21 @@ import com.gooddata.sdk.service.*; import com.gooddata.sdk.service.gdc.DataStoreException; import com.gooddata.sdk.service.gdc.DataStoreService; -import com.gooddata.sdk.service.project.model.ModelService; import org.apache.commons.lang3.RandomStringUtils; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriTemplate; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import static com.gooddata.sdk.common.util.Validate.notEmpty; -import static com.gooddata.sdk.common.util.Validate.notNull; -import static com.gooddata.sdk.common.util.Validate.notNullState; -import static java.lang.String.format; -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static org.springframework.util.StringUtils.isEmpty; - -/** - * Service to work with datasets, manifests and dataset uploads. - */ +import static com.gooddata.sdk.common.util.Validate.*; + public class DatasetService extends AbstractService { public static final UriTemplate UPLOADS_INFO_TEMPLATE = new UriTemplate(UploadsInfo.URI); @@ -50,52 +38,44 @@ public class DatasetService extends AbstractService { private final DataStoreService dataStoreService; - public DatasetService(final RestTemplate restTemplate, final DataStoreService dataStoreService, - final GoodDataSettings settings) { - super(restTemplate, settings); + public DatasetService(final WebClient webClient, final DataStoreService dataStoreService, final GoodDataSettings settings) { + super(webClient, settings); this.dataStoreService = dataStoreService; } /** - * Obtains manifest from given project by given datasetId - * - * @param project project to which manifest belongs - * @param datasetId id of dataset - * @return manifest for dataset - * @throws DatasetNotFoundException when manifest can't be found (doesn't exist) - * @throws DatasetException in case the API call failure + * Obtains manifest for the given dataset in the specified project. */ public DatasetManifest getDatasetManifest(Project project, String datasetId) { notNull(project, "project"); notNull(project.getId(), "project.id"); notEmpty(datasetId, "datasetId"); try { - return restTemplate.getForObject(DatasetManifest.URI, DatasetManifest.class, project.getId(), datasetId); + String uri = DatasetManifest.URI.replace("{projectId}", project.getId()).replace("{datasetId}", datasetId); + DatasetManifest manifest = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(DatasetManifest.class) + .block(); + if (manifest == null) { + throw new DatasetNotFoundException(datasetId, null); + } + return manifest; } catch (GoodDataRestException e) { if (e.getStatusCode() == 404) { throw new DatasetNotFoundException(datasetId, e); } else { throw new DatasetException("Unable to get manifest", datasetId, e); } - } catch (RestClientException e) { + } catch (Exception e) { throw new DatasetException("Unable to get manifest", datasetId, e); } } /** - * Loads dataset into platform. Uploads given dataset and manifest to staging area and triggers ETL pull. - * The call is asynchronous returning {@link FutureResult} to let caller wait for results. - * Uploaded files are deleted from staging area when finished. - * - * @param project project to which dataset belongs - * @param manifest dataset manifest - * @param dataset dataset to upload - * @return {@link FutureResult} of the task, which can throw {@link DatasetException} - * in case the ETL pull task fails - * @throws DatasetException if there is a problem to serialize manifest or upload dataset + * Loads a dataset into the platform: uploads the dataset and manifest to staging and triggers ETL pull. */ - public FutureResult loadDataset(final Project project, final DatasetManifest manifest, - final InputStream dataset) { + public FutureResult loadDataset(final Project project, final DatasetManifest manifest, final InputStream dataset) { notNull(project, "project"); notNull(dataset, "dataset"); notNull(manifest, "manifest"); @@ -104,15 +84,6 @@ public FutureResult loadDataset(final Project project, final DatasetManife return loadDatasets(project, manifest); } - /** - * Gets DatasetManifest (using {@link #getDatasetManifest(Project, String)} - * first and then calls {@link #loadDataset(Project, DatasetManifest, java.io.InputStream)} - * - * @param project project to which dataset belongs - * @param datasetId datasetId to obtain a manifest - * @param dataset dataset to upload - * @return {@link FutureResult} of the task - */ public FutureResult loadDataset(Project project, String datasetId, InputStream dataset) { notNull(project, "project"); notEmpty(datasetId, "datasetId"); @@ -121,20 +92,11 @@ public FutureResult loadDataset(Project project, String datasetId, InputSt } public FutureResult loadDatasets(final Project project, DatasetManifest... datasets) { - return loadDatasets(project, asList(datasets)); + return loadDatasets(project, List.of(datasets)); } /** - * Loads datasets into platform. Uploads given datasets and their manifests to staging area and triggers ETL pull. - * The call is asynchronous returning {@link FutureResult} to let caller wait for results. - * Uploaded files are deleted from staging area when finished. - * - * @param project project to which dataset belongs - * @param datasets map dataset manifests - * @return {@link FutureResult} of the task, which can throw {@link DatasetException} - * in case the ETL pull task fails - * @throws DatasetException if there is a problem to serialize manifest or upload dataset - * @see batch upload reference + * Loads multiple datasets and their manifests to staging, then triggers ETL pull. */ public FutureResult loadDatasets(final Project project, final Collection datasets) { if (dataStoreService == null) { @@ -152,13 +114,13 @@ public FutureResult loadDatasets(final Project project, final Collection datasets) notEmpty(datasets, "datasets"); for (DatasetManifest datasetManifest : datasets) { if (datasetManifest.getSource() == null) { - throw new IllegalArgumentException(format("Source for dataset '%s' is null", datasetManifest.getDataSet())); + throw new IllegalArgumentException(String.format("Source for dataset '%s' is null", datasetManifest.getDataSet())); } if (datasetManifest.getFile() == null) { - throw new IllegalArgumentException(format("File for dataset '%s' is null", datasetManifest.getDataSet())); + throw new IllegalArgumentException(String.format("File for dataset '%s' is null", datasetManifest.getDataSet())); } - if (isEmpty(datasetManifest.getDataSet())) { + if (org.springframework.util.StringUtils.isEmpty(datasetManifest.getDataSet())) { throw new IllegalArgumentException("Dataset name is empty."); } } @@ -180,15 +142,21 @@ private void validateUploadManifests(final Collection datasets) private FutureResult pullLoad(Project project, final String dirPath, final Collection datasets) { notNull(project.getId(), "project.id"); - final PullTask pullTask = restTemplate - .postForObject(Pull.URI, new Pull(dirPath), PullTask.class, project.getId()); + + // Trigger ETL pull via WebClient POST + PullTask pullTask = webClient.post() + .uri(Pull.URI.replace("{projectId}", project.getId())) + .bodyValue(new Pull(dirPath)) + .retrieve() + .bodyToMono(PullTask.class) + .block(); return new PollResult<>(this, new AbstractPollHandler( notNullState(pullTask, "created pull task").getPollUri(), TaskStatus.class, Void.class) { @Override public void handlePollResult(TaskStatus pollResult) { if (!pollResult.isSuccess()) { - final String message = isEmpty(pollResult.getMessages()) + final String message = org.springframework.util.StringUtils.isEmpty(pollResult.getMessages()) ? String.format(ETL_PULL_DEFAULT_ERROR_MESSAGE, pollResult.getStatus()) : pollResult.getMessages().toString(); throw new DatasetException(message, datasets); @@ -206,47 +174,51 @@ protected void onFinish() { try { dataStoreService.delete(dirPath); } catch (DataStoreException ignored) { - // todo log? + // TODO: log error } } }); } /** - * Lists datasets (links) in project. Returns empty list in case there are no datasets. - * - * @param project project to list datasets in - * @return collection of dataset links or empty list + * Lists all datasets (links) in a project. Returns empty list if there are no datasets. */ public Collection listDatasetLinks(final Project project) { notNull(project, "project"); notNull(project.getId(), "project.id"); try { - final DatasetLinks result = restTemplate.getForObject(DatasetLinks.URI, DatasetLinks.class, project.getId()); + String uri = DatasetLinks.URI.replace("{projectId}", project.getId()); + DatasetLinks result = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(DatasetLinks.class) + .block(); if (result == null) { throw new GoodDataException("Empty response from API call"); } else if (result.getLinks() == null) { - return emptyList(); + return java.util.Collections.emptyList(); } return result.getLinks(); - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to list datasets for project " + project.getId(), e); } } /** - * Optimize SLI hash. This feature is useful only if data warehouse was reduced somehow. Remove unused values from - * the existing SLI hash. - * - * @param project project to optimize SLI hash in - * @return {@link FutureResult} of the task + * Optimize SLI hash for a project. */ public FutureResult optimizeSliHash(final Project project) { notNull(project, "project"); notNull(project.getId(), "project.id"); - final UriResponse uriResponse = restTemplate.postForObject( - EtlMode.URL, new EtlMode(EtlModeType.SLI, LookupMode.RECREATE), UriResponse.class, project.getId()); + UriResponse uriResponse = webClient.post() + .uri(EtlMode.URL.replace("{projectId}", project.getId())) + .bodyValue(new EtlMode(EtlModeType.SLI, LookupMode.RECREATE)) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); + + final String errorMessage = String.format("Unable to optimize SLI hash for project '%s'", project.getId()); return new PollResult<>(this, new AbstractPollHandler( @@ -255,49 +227,33 @@ public FutureResult optimizeSliHash(final Project project) { @Override public void handlePollResult(final TaskStatus pollResult) { if (!pollResult.isSuccess()) { - throw new GoodDataException("Unable to optimize SLI hash for project " + project.getId()); + throw new GoodDataException(errorMessage); } setResult(null); } - @Override - public boolean isFinished(final ClientHttpResponse response) throws IOException { - if (!super.isFinished(response)) { - return false; - } - final TaskStatus maqlDdlTaskStatus = extractData(response, TaskStatus.class); - if (maqlDdlTaskStatus.isSuccess()) { - return true; - } - throw new GoodDataException("Unable to optimize SLI hash: " + maqlDdlTaskStatus.getMessages()); - } - @Override public void handlePollException(final GoodDataRestException e) { - throw new GoodDataException("Unable to optimize SLI hash: " + getPollingUri(), e); + throw new GoodDataException(errorMessage, e); } - }); - } /** - * Update project data with the given update script (MAQL). This method can be used for data manipulation only, - * for model changes use {@link ModelService#updateProjectModel}. - * - * @param project project to be updated - * @param maqlDml update script to be executed in the project - * @return poll result - * @see ModelService#updateProjectModel + * Update project data with the given MAQL script. */ public FutureResult updateProjectData(final Project project, final String maqlDml) { notNull(project, "project"); notNull(project.getId(), "project.id"); - final UriResponse uriResponse = restTemplate.postForObject( - MaqlDml.URI, new MaqlDml(maqlDml), UriResponse.class, project.getId()); + UriResponse uriResponse = webClient.post() + .uri(MaqlDml.URI.replace("{projectId}", project.getId())) + .bodyValue(new MaqlDml(maqlDml)) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); - final String errorMessage = format("Unable to update data for project '%s'", project.getId()); + final String errorMessage = String.format("Unable to update data for project '%s'", project.getId()); return new PollResult<>(this, new AbstractPollHandler( @@ -310,113 +266,103 @@ public void handlePollResult(final TaskState pollResult) { } setResult(null); } - - @Override - public boolean isFinished(final ClientHttpResponse response) throws IOException { - final TaskState taskState = extractData(response, TaskState.class); - if (taskState.isSuccess()) { - return true; - } else if (!taskState.isFinished()) { - return false; - } - throw new GoodDataException(errorMessage + ": " + taskState.getMessage()); - } - @Override public void handlePollException(final GoodDataRestException e) { - throw new GoodDataException(errorMessage + ": " + getPollingUri(), e); + throw new GoodDataException(errorMessage, e); } }); } /** - * Lists all uploads for the dataset with the given identifier in the given project. Returns empty list if there - * are no uploads for the given dataset. - * - * @param project GoodData project - * @param datasetId dataset identifier - * @return collection of {@link Upload} objects or empty list + * Lists all uploads for a dataset in a project. */ public Collection listUploadsForDataset(Project project, String datasetId) { final UploadsInfo.DataSet dataSet = getDataSetInfo(project, datasetId); - if (isEmpty(dataSet.getUploadsUri())) { - return emptyList(); + if (org.springframework.util.StringUtils.isEmpty(dataSet.getUploadsUri())) { + return java.util.Collections.emptyList(); } try { - final Uploads result = restTemplate.getForObject(dataSet.getUploadsUri(), Uploads.class); + Uploads result = webClient.get() + .uri(dataSet.getUploadsUri()) + .retrieve() + .bodyToMono(Uploads.class) + .block(); if (result == null) { throw new GoodDataException("Empty response from '" + dataSet.getUploadsUri() + "'."); } else if (result.items() == null){ - return emptyList(); + return java.util.Collections.emptyList(); } return result.items(); - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get '" + dataSet.getUploadsUri() + "'.", e); } } /** - * Returns last upload for the dataset with given identifier in the given project. Returns null if the last upload - * doesn't exist. - * - * @param project GoodData project - * @param datasetId dataset identifier - * @return last dataset upload or {@code null} if the upload doesn't exist + * Returns the last upload for a dataset in a project, or null if none exists. */ public Upload getLastUploadForDataset(Project project, String datasetId) { final UploadsInfo.DataSet dataSet = getDataSetInfo(project, datasetId); - if (isEmpty(dataSet.getLastUploadUri())) { + if (!org.springframework.util.StringUtils.hasLength(dataSet.getLastUploadUri())) { return null; } - + try { - return restTemplate.getForObject(dataSet.getLastUploadUri(), Upload.class); - } catch (RestClientException e) { + return webClient.get() + .uri(dataSet.getLastUploadUri()) + .retrieve() + .bodyToMono(Upload.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to get '" + dataSet.getLastUploadUri() + "'."); } } /** - * Returns global upload statistics for the given project. - * - * @param project GoodData project - * @return {@link UploadStatistics} object with project's upload statistics + * Returns upload statistics for the project. */ public UploadStatistics getUploadStatistics(Project project) { notNull(project, "project"); notNull(project.getId(), "project.id"); try { - return restTemplate.getForObject(UploadStatistics.URI, UploadStatistics.class, project.getId()); - } catch (RestClientException e) { + String uri = UploadStatistics.URI.replace("{projectId}", project.getId()); + return webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(UploadStatistics.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to get dataset uploads statistics.", e); } } /** - * Returns {@link UploadsInfo.DataSet} object containing upload information for the given dataset in the given project. - * - * Package-private for testing purposes. + * Returns DataSet information for the given dataset and project. */ - UploadsInfo.DataSet getDataSetInfo(Project project, String datasetId) { + protected UploadsInfo.DataSet getDataSetInfo(Project project, String datasetId) { notNull(project, "project"); notNull(project.getId(), "project.id"); notEmpty(datasetId, "datasetId"); final URI uploadsInfoUri = UPLOADS_INFO_TEMPLATE.expand(project.getId()); try { - final UploadsInfo uploadsInfo = restTemplate.getForObject(uploadsInfoUri, UploadsInfo.class); + UploadsInfo uploadsInfo = webClient.get() + .uri(uploadsInfoUri) + .retrieve() + .bodyToMono(UploadsInfo.class) + .block(); if (uploadsInfo == null) { throw new GoodDataException("Empty response from '" + uploadsInfoUri.toString() + "'."); } return uploadsInfo.getDataSet(datasetId); - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get '" + uploadsInfoUri.toString() + "'.", e); } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/executeafm/ExecuteAfmService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/executeafm/ExecuteAfmService.java index b648993ca..695472db9 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/executeafm/ExecuteAfmService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/executeafm/ExecuteAfmService.java @@ -14,10 +14,10 @@ import com.gooddata.sdk.model.executeafm.result.ExecutionResult; import com.gooddata.sdk.model.project.Project; import com.gooddata.sdk.service.*; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriComponentsBuilder; + import static com.gooddata.sdk.common.util.Validate.notNull; /** @@ -49,13 +49,16 @@ public class ExecuteAfmService extends AbstractService { */ public static final String RESULT_LIMIT = "limit"; + private final WebClient webClient; + /** * Constructor. - * @param restTemplate rest template + * @param webClient web client * @param settings settings */ - public ExecuteAfmService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public ExecuteAfmService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); + this.webClient = webClient; } /** @@ -66,22 +69,16 @@ public ExecuteAfmService(final RestTemplate restTemplate, final GoodDataSettings */ public ExecutionResponse executeAfm(final Project project, final Execution execution) { final String projectId = notNull(notNull(project, "project").getId(), "projectId"); - final ExecutionResponse response; try { - response = restTemplate.postForObject( - AFM_EXECUTION_URI, - notNull(execution, "execution"), - ExecutionResponse.class, - projectId); - } catch (GoodDataException | RestClientException e) { + return webClient.post() + .uri(AFM_EXECUTION_URI, projectId) + .bodyValue(notNull(execution, "execution")) + .retrieve() + .bodyToMono(ExecutionResponse.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to execute AFM", e); } - - if (response == null) { - throw new GoodDataException("Empty response when execution posted to API"); - } - - return response; } /** @@ -92,22 +89,16 @@ public ExecutionResponse executeAfm(final Project project, final Execution execu */ public ExecutionResponse executeVisualization(final Project project, final VisualizationExecution execution) { final String projectId = notNull(notNull(project, "project").getId(), "projectId"); - final ExecutionResponse response; try { - response = restTemplate.postForObject( - VISUALIZATION_EXECUTION_URI, - notNull(execution, "execution"), - ExecutionResponse.class, - projectId); - } catch (GoodDataException | RestClientException e) { + return webClient.post() + .uri(VISUALIZATION_EXECUTION_URI, projectId) + .bodyValue(notNull(execution, "execution")) + .retrieve() + .bodyToMono(ExecutionResponse.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to execute visualization", e); } - - if (response == null) { - throw new GoodDataException("Empty response when execution posted to API"); - } - - return response; } /** diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/export/ExportService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/export/ExportService.java index 24c84d373..9b9b24125 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/export/ExportService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/export/ExportService.java @@ -20,11 +20,9 @@ import com.gooddata.sdk.model.md.report.ReportDefinition; import com.gooddata.sdk.model.project.Project; import com.gooddata.sdk.service.*; -import org.springframework.http.HttpEntity; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriTemplate; import java.io.IOException; @@ -32,42 +30,29 @@ import static com.gooddata.sdk.common.util.Validate.notNull; import static com.gooddata.sdk.common.util.Validate.notNullState; -import static org.springframework.http.HttpMethod.GET; -import static org.springframework.http.HttpMethod.POST; /** - * Export project data - * + * Export project data using WebClient (Spring 6, JDK 17) */ public class ExportService extends AbstractService { public static final String EXPORTING_URI = "/gdc/exporter/executor"; - private static final String CLIENT_EXPORT_URI = "/gdc/projects/{projectId}/clientexport"; - private static final String RAW_EXPORT_URI = "/gdc/projects/{projectId}/execute/raw"; - public static final UriTemplate OBJ_TEMPLATE = new UriTemplate(Obj.OBJ_URI); public static final UriTemplate PROJECT_TEMPLATE = new UriTemplate(Project.URI); /** * Service for data export - * @param restTemplate REST template + * @param webClient WebClient * @param settings settings */ - public ExportService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public ExportService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** * Export the given report definition in the given format to the given output stream - * - * @param reportDefinition report definition - * @param format export format - * @param output target - * @return polling result - * @throws NoDataExportException in case report contains no data - * @throws ExportException on error */ public FutureResult export(final ReportDefinition reportDefinition, final ExportFormat format, final OutputStream output) { @@ -78,13 +63,6 @@ public FutureResult export(final ReportDefinition reportDefinition, final /** * Export the given report in the given format to the given output stream - * - * @param report report - * @param format export format - * @param output target - * @return polling result - * @throws NoDataExportException in case report contains no data - * @throws ExportException on error */ public FutureResult export(final Report report, final ExportFormat format, final OutputStream output) { @@ -100,44 +78,54 @@ private FutureResult exportReport(final ReportRequest request, final Expor final String uri = exportReport(execResult, format); return new PollResult<>(this, new SimplePollHandler(uri, Void.class) { @Override - public boolean isFinished(ClientHttpResponse response) throws IOException { - switch (response.getStatusCode()) { - case OK: - return true; - case ACCEPTED: - return false; - case NO_CONTENT: - throw new NoDataExportException(); - default: - throw new ExportException("Unable to export report, unknown HTTP response code: " + response.getStatusCode()); + public boolean isFinished(ClientResponse response) { + int code = response.statusCode().value(); + if (code == 200) { + return true; + } else if (code == 202) { + return false; + } else if (code == 204) { + throw new NoDataExportException(); + } else { + throw new ExportException("Unable to export report, unknown HTTP response code: " + code); } } @Override - public void handlePollException(final GoodDataRestException e) { - throw new ExportException("Unable to export report", e); + protected void onFinish() { + // Download file using WebClient and write to OutputStream + byte[] data = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(byte[].class) + .block(); + if (data != null) { + try { + output.write(data); + } catch (IOException e) { + throw new ExportException("Unable to write export to output stream", e); + } + } } @Override - protected void onFinish() { - try { - restTemplate.execute(uri, GET, null, new OutputStreamResponseExtractor(output)); - } catch (GoodDataException | RestClientException e) { - throw new ExportException("Unable to export report", e); - } + public void handlePollException(final GoodDataRestException e) { + throw new ExportException("Unable to export report", e); } }); } protected JsonNode executeReport(final String executionUri, final ReportRequest request) { try { - final ResponseEntity entity = restTemplate - .exchange(executionUri, POST, new HttpEntity<>(request), String.class); - return mapper.readTree(entity.getBody()); - } catch (GoodDataException | RestClientException e) { + String responseBody = webClient.post() + .uri(executionUri) + .bodyValue(request) + .retrieve() + .bodyToMono(String.class) + .block(); + return mapper.readTree(responseBody); + } catch (Exception e) { throw new ExportException("Unable to execute report", e); - } catch (IOException e) { - throw new ExportException("Unable to read execution result", e); } } @@ -152,21 +140,20 @@ private String exportReport(final JsonNode execResult, final ExportFormat format root.set("result_req", child); try { - return notNullState(restTemplate.postForObject(EXPORTING_URI, root, UriResponse.class), "exported report").getUri(); - } catch (GoodDataException | RestClientException e) { + UriResponse uriResponse = webClient.post() + .uri(EXPORTING_URI) + .bodyValue(root) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); + return notNullState(uriResponse, "exported report").getUri(); + } catch (Exception e) { throw new ExportException("Unable to export report", e); } } /** * Export the given dashboard tab in PDF format to the given output stream - * - * @param endpoint endpoint for which the export is generated - * @param dashboard dashboard - * @param tab tab - * @param output output - * @return polling result - * @throws ExportException if export fails */ public FutureResult exportPdf(final GoodDataEndpoint endpoint, final ProjectDashboard dashboard, final Tab tab, final OutputStream output) { notNull(endpoint, "endpoint"); @@ -181,31 +168,43 @@ public FutureResult exportPdf(final GoodDataEndpoint endpoint, final Proje final ClientExport export = new ClientExport(endpoint.toUri(), projectUri, dashboardUri, tab.getIdentifier()); final AsyncTask task; try { - task = restTemplate.postForObject(CLIENT_EXPORT_URI, export, AsyncTask.class, projectId); - } catch (RestClientException | GoodDataRestException e) { + task = webClient.post() + .uri(CLIENT_EXPORT_URI.replace("{projectId}", projectId)) + .bodyValue(export) + .retrieve() + .bodyToMono(AsyncTask.class) + .block(); + } catch (Exception e) { throw new ExportException("Unable to export dashboard: " + dashboardUri, e); } return new PollResult<>(this, new SimplePollHandler(notNullState(task, "export pdf task").getUri(), Void.class) { @Override - public boolean isFinished(ClientHttpResponse response) throws IOException { - switch (response.getStatusCode()) { - case OK: - return true; - case ACCEPTED: - return false; - default: - throw new ExportException("Unable to export dashboard: " + dashboardUri + - ", unknown HTTP response code: " + response.getStatusCode()); + public boolean isFinished(ClientResponse response) { + int code = response.statusCode().value(); + if (code == 200) { + return true; + } else if (code == 202) { + return false; + } else { + throw new ExportException("Unable to export dashboard: " + dashboardUri + + ", unknown HTTP response code: " + code); } } @Override protected void onFinish() { - try { - restTemplate.execute(task.getUri(), GET, null, new OutputStreamResponseExtractor(output)); - } catch (GoodDataException | RestClientException e) { - throw new ExportException("Unable to export dashboard: " + dashboardUri, e); + byte[] data = webClient.get() + .uri(task.getUri()) + .retrieve() + .bodyToMono(byte[].class) + .block(); + if (data != null) { + try { + output.write(data); + } catch (IOException e) { + throw new ExportException("Unable to write dashboard export to stream", e); + } } } @@ -218,10 +217,6 @@ public void handlePollException(final GoodDataRestException e) { /** * Export the given Report using the raw export (without columns/rows limitations) - * @param report report - * @param output output - * @return polling result - * @throws ExportException in case export fails */ public FutureResult exportCsv(final Report report, final OutputStream output) { notNull(report, "report"); @@ -230,10 +225,6 @@ public FutureResult exportCsv(final Report report, final OutputStream outp /** * Export the given Report Definition using the raw export (without columns/rows limitations) - * @param definition report definition - * @param output output - * @return polling result - * @throws ExportException in case export fails */ public FutureResult exportCsv(final ReportDefinition definition, final OutputStream output) { final ReportRequest request = new ExecuteReportDefinition(definition); @@ -246,40 +237,51 @@ private FutureResult exportCsv(final AbstractObj obj, final ReportRequest notNull(output, "output"); final String projectId = extractProjectId(obj); - final String uri = obj.getUri(); - - final UriResponse response; + final String uri; try { - response = restTemplate.postForObject(RAW_EXPORT_URI, request, UriResponse.class, projectId); - } catch (RestClientException | GoodDataRestException e) { - throw new ExportException("Unable to export: " + uri); - } - if (response == null || response.getUri() == null) { - throw new ExportException("Empty response, unable to export: " + uri); + UriResponse response = webClient.post() + .uri(RAW_EXPORT_URI.replace("{projectId}", projectId)) + .bodyValue(request) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); + if (response == null || response.getUri() == null) { + throw new ExportException("Empty response, unable to export: " + obj.getUri()); + } + uri = response.getUri(); + } catch (Exception e) { + throw new ExportException("Unable to export: " + obj.getUri(), e); } - return new PollResult<>(this, new SimplePollHandler(response.getUri(), Void.class) { + return new PollResult<>(this, new SimplePollHandler(uri, Void.class) { @Override - public boolean isFinished(ClientHttpResponse response) throws IOException { - switch (response.getStatusCode()) { - case OK: - return true; - case ACCEPTED: - return false; - case NO_CONTENT: - throw new NoDataExportException(); - default: - throw new ExportException("Unable to export: " + uri + - ", unknown HTTP response code: " + response.getStatusCode()); + public boolean isFinished(ClientResponse response) { + int code = response.statusCode().value(); + if (code == 200) { // OK + return true; + } else if (code == 202) { // ACCEPTED + return false; + } else if (code == 204) { // NO_CONTENT + throw new NoDataExportException(); + } else { + throw new ExportException("Unable to export: " + uri + + ", unknown HTTP response code: " + code); } } @Override protected void onFinish() { - try { - restTemplate.execute(getPolling(), GET, null, new OutputStreamResponseExtractor(output)); - } catch (GoodDataException | RestClientException e) { - throw new ExportException("Unable to export: " + uri, e); + byte[] data = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(byte[].class) + .block(); + if (data != null) { + try { + output.write(data); + } catch (IOException e) { + throw new ExportException("Unable to write export to output stream", e); + } } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/featureflag/FeatureFlagService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/featureflag/FeatureFlagService.java index 6ad32cbad..c5326c6ed 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/featureflag/FeatureFlagService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/featureflag/FeatureFlagService.java @@ -14,9 +14,9 @@ import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; import com.gooddata.sdk.service.hierarchicalconfig.HierarchicalConfigService; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriTemplate; +import reactor.core.publisher.Mono; import java.net.URI; @@ -24,7 +24,7 @@ import static com.gooddata.sdk.common.util.Validate.notNull; /** - * Provides feature flag management. Feature flag is a boolean flag used for enabling / disabling some specific feature + * Provides feature flag management. Feature flag is a boolean flag used for enabling/disabling some specific feature * of GoodData platform. It can be used in various scopes (per project, per project group, per user, global etc.). * @deprecated Use {@link HierarchicalConfigService}. */ @@ -37,70 +37,60 @@ public class FeatureFlagService extends AbstractService { /** * Constructs service for GoodData feature flags management. - * @param restTemplate RESTful HTTP Spring template + * @param webClient WebClient for HTTP communication * @param settings settings */ - public FeatureFlagService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public FeatureFlagService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** - * Returns aggregated feature flags for given project and current user (aggregates global, project group, project - * and user feature flags). - * It doesn't matter whether feature flag is enabled or not, it'll be included in both cases. - * - * @param project project, cannot be null - * @return aggregated feature flags for given project and current user + * Returns aggregated feature flags for given project and current user. * @deprecated Use {@link HierarchicalConfigService#listProjectConfigItems(Project)}. */ public FeatureFlags listFeatureFlags(final Project project) { notNull(project, "project"); try { - final FeatureFlags featureFlags = restTemplate - .getForObject(AGGREGATED_FEATURE_FLAGS_TEMPLATE.expand(project.getId()), FeatureFlags.class); + FeatureFlags featureFlags = webClient.get() + .uri(AGGREGATED_FEATURE_FLAGS_TEMPLATE.expand(project.getId()).toString()) + .retrieve() + .bodyToMono(FeatureFlags.class) + .block(); if (featureFlags == null) { - throw new GoodDataException("empty response from API call"); + throw new GoodDataException("Empty response from API call"); } return featureFlags; - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to list aggregated feature flags for project ID=" + project.getId(), e); } } /** - * Returns project feature flags (only project scoped flags, use {@link #listFeatureFlags(Project)} for aggregated - * flags from all scopes) for given project. - * It doesn't matter whether feature flag is enabled or not, it'll be included in both cases. - * - * @param project project, cannot be null - * @return list of all feature flags for given project + * Returns project feature flags for given project. * @deprecated Use {@link HierarchicalConfigService#listProjectConfigItems(Project)}. */ public ProjectFeatureFlags listProjectFeatureFlags(final Project project) { notNull(project, "project"); try { - final ProjectFeatureFlags projectFeatureFlags = restTemplate - .getForObject(PROJECT_FEATURE_FLAGS_TEMPLATE.expand(project.getId()), ProjectFeatureFlags.class); + ProjectFeatureFlags projectFeatureFlags = webClient.get() + .uri(PROJECT_FEATURE_FLAGS_TEMPLATE.expand(project.getId()).toString()) + .retrieve() + .bodyToMono(ProjectFeatureFlags.class) + .block(); if (projectFeatureFlags == null) { - throw new GoodDataException("empty response from API call"); + throw new GoodDataException("Empty response from API call"); } return projectFeatureFlags; - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to list project feature flags for project ID=" + project.getId(), e); } } /** - * Returns project feature flag (only project scoped flags, use {@link #listFeatureFlags(Project)} for aggregated - * flags from all scopes) for given project by its unique name (aka "key"). - * It doesn't matter whether feature flag is enabled or not, it'll be included in both cases. - * - * @param project project, cannot be null - * @param featureFlagName unique name (key) of feature flag, cannot be empty - * @return feature flag for given project with given name (key) + * Returns project feature flag for given project by its unique name (key). * @deprecated Use {@link HierarchicalConfigService#getProjectConfigItem(Project, String)}. */ public ProjectFeatureFlag getProjectFeatureFlag(final Project project, final String featureFlagName) { @@ -109,20 +99,13 @@ public ProjectFeatureFlag getProjectFeatureFlag(final Project project, final Str try { return getProjectFeatureFlag(getProjectFeatureFlagUri(project, featureFlagName)); - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get project feature flag: " + featureFlagName, e); } } /** * Creates new feature flag for given project. - *

- * Usually, it doesn't make sense to create feature flag that is disabled because - * this is the same as having no feature flag at all. - * - * @param project project for which the feature flag should be created, cannot be null - * @param flag feature flag to be created, cannot be null - * @return created feature flag * @deprecated Use {@link HierarchicalConfigService#setProjectConfigItem(Project, ConfigItem)}. */ public ProjectFeatureFlag createProjectFeatureFlag(final Project project, final ProjectFeatureFlag flag) { @@ -132,22 +115,25 @@ public ProjectFeatureFlag createProjectFeatureFlag(final Project project, final final String featureFlagsUri = PROJECT_FEATURE_FLAGS_TEMPLATE.expand(project.getId()).toString(); try { - final URI featureFlagUri = restTemplate.postForLocation(featureFlagsUri, flag); + URI featureFlagUri = webClient.post() + .uri(featureFlagsUri) + .bodyValue(flag) + .retrieve() + .toBodilessEntity() + .map(response -> response.getHeaders().getLocation()) + .block(); + if (featureFlagUri == null) { throw new GoodDataException("URI of new project feature flag can't be null"); } return getProjectFeatureFlag(featureFlagUri.toString()); - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to create project feature flag: " + flag, e); } } /** * Updates existing project feature flag. - * Note that it doesn't make sense to update any other property than {@link ProjectFeatureFlag#isEnabled()}. - * - * @param flag feature flag to be updated, cannot be null and it has to contain URI - * @return updated feature flag * @deprecated Use {@link HierarchicalConfigService#setProjectConfigItem(Project, ConfigItem)}. */ public ProjectFeatureFlag updateProjectFeatureFlag(final ProjectFeatureFlag flag) { @@ -155,17 +141,21 @@ public ProjectFeatureFlag updateProjectFeatureFlag(final ProjectFeatureFlag flag notEmpty(flag.getUri(), "flag.uri"); try { - restTemplate.put(flag.getUri(), flag); + webClient.put() + .uri(flag.getUri()) + .bodyValue(flag) + .retrieve() + .toBodilessEntity() + .block(); + return getProjectFeatureFlag(flag.getUri()); - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to update project feature flag: " + flag, e); } } /** * Deletes existing project feature flag. - * - * @param flag existing project feature flag with links set properly, cannot be null * @deprecated Use {@link HierarchicalConfigService#removeProjectConfigItem(ConfigItem)}. */ public void deleteProjectFeatureFlag(final ProjectFeatureFlag flag) { @@ -173,19 +163,27 @@ public void deleteProjectFeatureFlag(final ProjectFeatureFlag flag) { notEmpty(flag.getUri(), "flag URI"); try { - restTemplate.delete(flag.getUri()); - } catch (GoodDataException | RestClientException e) { + webClient.delete() + .uri(flag.getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to delete project feature flag: " + flag, e); } } - String getProjectFeatureFlagUri(final Project project, final String flagName) { return PROJECT_FEATURE_FLAG_TEMPLATE.expand(project.getId(), flagName).toString(); } private ProjectFeatureFlag getProjectFeatureFlag(final String flagUri) { - final ProjectFeatureFlag result = restTemplate.getForObject(flagUri, ProjectFeatureFlag.class); + ProjectFeatureFlag result = webClient.get() + .uri(flagUri) + .retrieve() + .bodyToMono(ProjectFeatureFlag.class) + .block(); + if (result == null) { throw new GoodDataException("Project feature flag cannot be retrieved from URI " + flagUri); } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/gdc/DataStoreService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/gdc/DataStoreService.java index 993ef1f1b..6f8b36219 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/gdc/DataStoreService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/gdc/DataStoreService.java @@ -5,63 +5,44 @@ */ package com.gooddata.sdk.service.gdc; -import com.github.sardine.impl.SardineException; -import com.gooddata.sdk.common.GoodDataRestException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import com.gooddata.sdk.common.UriPrefixer; import com.gooddata.sdk.service.httpcomponents.SingleEndpointGoodDataRestProvider; -import org.apache.http.*; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.NonRepeatableRequestException; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.entity.InputStreamEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.message.BasicHeader; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.HTTP; -import org.apache.http.protocol.HttpContext; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; +import org.springframework.http.HttpStatusCode; +import org.springframework.web.reactive.function.client.ClientResponse; + -import java.io.IOException; import java.io.InputStream; import java.net.URI; -import java.util.*; import java.util.function.Supplier; import static com.gooddata.sdk.common.util.Validate.notEmpty; import static com.gooddata.sdk.common.util.Validate.notNull; -/** - * Uploads, downloads, deletes, ... at datastore - */ +@Component public class DataStoreService { - private final GdcSardine sardine; private final Supplier stagingUriSupplier; private final URI gdcUri; - private final RestTemplate restTemplate; - + private final WebClient webClient; private UriPrefixer prefixer; - - /** - * Creates new DataStoreService - * @param restProvider restProvider to make datastore connection - * @param stagingUriSupplier used to obtain datastore URI - */ - public DataStoreService(SingleEndpointGoodDataRestProvider restProvider, Supplier stagingUriSupplier) { - notNull(restProvider, "restProvider"); + @Autowired + public DataStoreService(SingleEndpointGoodDataRestProvider restProvider, + Supplier stagingUriSupplier, + WebClient webClient) { this.stagingUriSupplier = notNull(stagingUriSupplier, "stagingUriSupplier"); this.gdcUri = URI.create(notNull(restProvider.getEndpoint(), "endpoint").toUri()); - this.restTemplate = notNull(restProvider.getRestTemplate(), "restTemplate"); - sardine = new GdcSardine(new CustomHttpClientBuilder(notNull(restProvider.getHttpClient(), "httpClient"))); + this.webClient = notNull(webClient, "webClient"); } private UriPrefixer getPrefixer() { @@ -69,360 +50,83 @@ private UriPrefixer getPrefixer() { final String uriString = stagingUriSupplier.get(); final URI uri = URI.create(uriString); prefixer = new UriPrefixer(uri.isAbsolute() ? uri : gdcUri.resolve(uriString)); - sardine.enablePreemptiveAuthentication(prefixer.getUriPrefix().getHost()); } return prefixer; } - /** - * Returns uri for given path (which is used by this service for upload, download or delete) - * @param path path the uri is constructed for - * @return uri for given path - */ public URI getUri(String path) { return getPrefixer().mergeUris(path); } - /** - * Uploads given stream to given datastore path - * @param path path where to upload to - * @param stream stream to upload - * @throws DataStoreException in case upload failed - */ + // Blocking upload (suitable for imperative code) public void upload(String path, InputStream stream) { notEmpty(path, "path"); notNull(stream, "stream"); - upload(getUri(path), stream); - } - - private void upload(URI url, InputStream stream) { - try { - // We need to use it this way, if we want to track request_id in the stacktrace. - InputStreamEntity entity = new InputStreamEntity(stream); - List

headers = Collections.singletonList(new BasicHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE)); - sardine.put(url.toString(), entity, headers, new GdcSardineResponseHandler()); - } catch (SardineException e) { - if (HttpStatus.INTERNAL_SERVER_ERROR.value() == e.getStatusCode()) { - // this error may occur when user issues request to WebDAV before SST and TT were obtained - // and WebDAV is deployed on a separate hostname - // see https://github.com/gooddata/gooddata-java/wiki/Known-limitations - throw new DataStoreException(createUnAuthRequestWarningMessage(url), e); - } else { - throw new DataStoreException("Unable to upload to " + url + " got status " + e.getStatusCode(), e); - } - } catch (NoHttpResponseException e) { - // this error may occur when user issues request to WebDAV before SST and TT were obtained - // and WebDAV is deployed on a separate hostname since R136 - // see https://github.com/gooddata/gooddata-java/wiki/Known-limitations - throw new DataStoreException(createUnAuthRequestWarningMessage(url), e); - } catch (IOException e) { - // this error may occur when user issues request to WebDAV before SST and TT were obtained - // and WebDAV deployed on the same hostname - // see https://github.com/gooddata/gooddata-java/wiki/Known-limitations - if (e.getCause() instanceof NonRepeatableRequestException) { - throw new DataStoreException(createUnAuthRequestWarningMessage(url), e); - } else { - throw new DataStoreException("Unable to upload to " + url, e); - } - } + uploadAsync(path, stream).block(); } - private String createUnAuthRequestWarningMessage(final URI url) { - return "Got 500 while uploading to " + url + "." - + "\nThis can be known limitation, see https://github.com/gooddata/gooddata-java/wiki/Known-limitations"; + // Non-blocking upload (for reactive use-cases) + public Mono uploadAsync(String path, InputStream stream) { + notEmpty(path, "path"); + notNull(stream, "stream"); + URI url = getUri(path); + return webClient.put() + .uri(url) + .body(BodyInserters.fromDataBuffers(DataBufferUtils.readInputStream(() -> stream, + new DefaultDataBufferFactory(), 4096))) + .retrieve() + .toBodilessEntity() + .then() + .onErrorMap(e -> wrapException("upload", url, e)); } - /** - * Download given path and return data as stream - * @param path path from where to download - * @return download stream - * @throws DataStoreException in case download failed - */ + // Blocking download public InputStream download(String path) { notEmpty(path, "path"); final URI uri = getUri(path); - try { - return sardine.get(uri.toString(), Collections.emptyList(), new GdcSardineResponseHandler()); - } catch (IOException e) { - throw new DataStoreException("Unable to download from " + uri, e); - } + return downloadAsync(path) + .map(dataBuffer -> dataBuffer.asInputStream(true)) + .block(); } - /** - * Delete given path from datastore. - * @param path path to delete - * @throws DataStoreException in case delete failed - */ - public void delete(String path) { + // Non-blocking download (returns DataBuffer) + public Mono downloadAsync(String path) { notEmpty(path, "path"); final URI uri = getUri(path); - try { - final ResponseEntity result = restTemplate.exchange(uri, HttpMethod.DELETE, org.springframework.http.HttpEntity.EMPTY, Void.class); - - // in case we get redirect (i.e. when we want to delete collection) we will follow redirect to the new location - if (HttpStatus.MOVED_PERMANENTLY.equals(result.getStatusCode())) { - restTemplate.exchange(result.getHeaders().getLocation(), HttpMethod.DELETE, org.springframework.http.HttpEntity.EMPTY, Void.class); - } - } catch (GoodDataRestException e) { - throw new DataStoreException("Unable to delete " + uri, e); - } + Flux dataBufferFlux = webClient.get() + .uri(uri) + .retrieve() + .onStatus( + HttpStatusCode::isError, + clientResponse -> clientResponse.bodyToMono(String.class) + .defaultIfEmpty("Unknown error") + .map(body -> new DataStoreException("Download failed: " + uri + " Body: " + body, null)) + ) + .bodyToFlux(DataBuffer.class); + + return DataBufferUtils.join(dataBufferFlux) + .onErrorMap(e -> wrapException("download", uri, e)); } - /** - * This class is needed to provide Sardine with instance of {@link CloseableHttpClient}, because - * used {@link com.gooddata.http.client.GoodDataHttpClient} is not Closeable at all (on purpose). - * Thanks to that we can use proper GoodData authentication mechanism instead of basic auth. - * - * It creates simple closeable wrapper around plain {@link HttpClient} where {@code close()} - * is implemented as noop (respectively for the response used). - */ - private static class CustomHttpClientBuilder extends HttpClientBuilder { - - private final HttpClient client; - - private CustomHttpClientBuilder(HttpClient client) { - this.client = client; - } - @Override - public CloseableHttpClient build() { - return new FakeCloseableHttpClient(client); - } + public void delete(String path) { + notEmpty(path, "path"); + final URI uri = getUri(path); + deleteAsync(path).block(); } - private static class FakeCloseableHttpClient extends CloseableHttpClient { - private final HttpClient client; - - private FakeCloseableHttpClient(HttpClient client) { - notNull(client, "client"); - this.client = client; - } - - @Override - protected CloseableHttpResponse doExecute(HttpHost target, HttpRequest request, HttpContext context) throws IOException, ClientProtocolException { - // nothing to do - this method is never called, because we override all methods from CloseableHttpClient - return null; - } - - @Override - public void close() throws IOException { - // nothing to close - wrappedClient doesn't have to implement CloseableHttpClient - } - - /** - * @deprecated because supertype's {@link HttpClient#getParams()} is deprecated. - */ - @Override - @Deprecated - public HttpParams getParams() { - return client.getParams(); - } - - /** - * @deprecated because supertype's {@link HttpClient#getConnectionManager()} is deprecated. - */ - @Override - @Deprecated - public ClientConnectionManager getConnectionManager() { - return client.getConnectionManager(); - } - - @Override - public CloseableHttpResponse execute(HttpUriRequest request) throws IOException, ClientProtocolException { - return new FakeCloseableHttpResponse(client.execute(request)); - } - - @Override - public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException, ClientProtocolException { - return new FakeCloseableHttpResponse(client.execute(request, context)); - } - - @Override - public CloseableHttpResponse execute(HttpHost target, HttpRequest request) throws IOException, ClientProtocolException { - return new FakeCloseableHttpResponse(client.execute(target, request)); - } - - @Override - public CloseableHttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException, ClientProtocolException { - return new FakeCloseableHttpResponse(client.execute(target, request, context)); - } - - @Override - public T execute(HttpUriRequest request, ResponseHandler responseHandler) throws IOException, ClientProtocolException { - return client.execute(request, responseHandler); - } - - @Override - public T execute(HttpUriRequest request, ResponseHandler responseHandler, HttpContext context) throws IOException, ClientProtocolException { - return client.execute(request, responseHandler, context); - } - - @Override - public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler) throws IOException, ClientProtocolException { - return client.execute(target, request, responseHandler); - } - - @Override - public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler, HttpContext context) throws IOException, ClientProtocolException { - return client.execute(target, request, responseHandler, context); - } + public Mono deleteAsync(String path) { + notEmpty(path, "path"); + final URI uri = getUri(path); + return webClient.delete() + .uri(uri) + .retrieve() + .toBodilessEntity() + .then() + .onErrorMap(e -> wrapException("delete", uri, e)); } - private static class FakeCloseableHttpResponse implements CloseableHttpResponse { - - private final HttpResponse wrappedResponse; - - public FakeCloseableHttpResponse(HttpResponse wrappedResponse) { - notNull(wrappedResponse, "wrappedResponse"); - this.wrappedResponse = wrappedResponse; - } - - @Override - public void close() throws IOException { - // nothing to close - wrappedClient doesn't have to implement CloseableHttpResponse - } - - @Override - public StatusLine getStatusLine() { - return wrappedResponse.getStatusLine(); - } - - @Override - public void setStatusLine(StatusLine statusline) { - wrappedResponse.setStatusLine(statusline); - } - - @Override - public void setStatusLine(ProtocolVersion ver, int code) { - wrappedResponse.setStatusLine(ver, code); - } - - @Override - public void setStatusLine(ProtocolVersion ver, int code, String reason) { - wrappedResponse.setStatusLine(ver, code, reason); - } - - @Override - public void setStatusCode(int code) throws IllegalStateException { - wrappedResponse.setStatusCode(code); - } - - @Override - public void setReasonPhrase(String reason) throws IllegalStateException { - wrappedResponse.setReasonPhrase(reason); - } - - @Override - public HttpEntity getEntity() { - return wrappedResponse.getEntity(); - } - - @Override - public void setEntity(HttpEntity entity) { - wrappedResponse.setEntity(entity); - } - - @Override - public Locale getLocale() { - return wrappedResponse.getLocale(); - } - - @Override - public void setLocale(Locale loc) { - wrappedResponse.setLocale(loc); - } - - @Override - public ProtocolVersion getProtocolVersion() { - return wrappedResponse.getProtocolVersion(); - } - - @Override - public boolean containsHeader(String name) { - return wrappedResponse.containsHeader(name); - } - - @Override - public Header[] getHeaders(String name) { - return wrappedResponse.getHeaders(name); - } - - @Override - public Header getFirstHeader(String name) { - return wrappedResponse.getFirstHeader(name); - } - - @Override - public Header getLastHeader(String name) { - return wrappedResponse.getLastHeader(name); - } - - @Override - public Header[] getAllHeaders() { - return wrappedResponse.getAllHeaders(); - } - - @Override - public void addHeader(Header header) { - wrappedResponse.addHeader(header); - } - - @Override - public void addHeader(String name, String value) { - wrappedResponse.addHeader(name, value); - } - - @Override - public void setHeader(Header header) { - wrappedResponse.setHeader(header); - } - - @Override - public void setHeader(String name, String value) { - wrappedResponse.setHeader(name, value); - } - - @Override - public void setHeaders(Header[] headers) { - wrappedResponse.setHeaders(headers); - } - - @Override - public void removeHeader(Header header) { - wrappedResponse.removeHeader(header); - } - - @Override - public void removeHeaders(String name) { - wrappedResponse.removeHeaders(name); - } - - @Override - public HeaderIterator headerIterator() { - return wrappedResponse.headerIterator(); - } - - @Override - public HeaderIterator headerIterator(String name) { - return wrappedResponse.headerIterator(name); - } - - /** - * @deprecated because supertype's {@link HttpMessage#getParams()} is deprecated. - */ - @Deprecated - @Override - public HttpParams getParams() { - return wrappedResponse.getParams(); - } - - /** - * @deprecated because supertype's {@link HttpMessage#setParams(HttpParams)} is deprecated. - */ - @Deprecated - @Override - public void setParams(HttpParams params) { - wrappedResponse.setParams(params); - } + private RuntimeException wrapException(String operation, URI uri, Throwable e) { + return new DataStoreException("Unable to " + operation + " from " + uri, e); } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/gdc/GdcService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/gdc/GdcService.java index 072129007..bd9af76f1 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/gdc/GdcService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/gdc/GdcService.java @@ -9,16 +9,19 @@ import com.gooddata.sdk.model.gdc.RootLinks; import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; /** * Service to work with GoodData API root. */ public class GdcService extends AbstractService { - public GdcService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + + // WebClient is injected instead of RestTemplate + public GdcService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** @@ -28,10 +31,15 @@ public GdcService(final RestTemplate restTemplate, final GoodDataSettings settin */ public RootLinks getRootLinks() { try { - return restTemplate.getForObject(RootLinks.URI, RootLinks.class); - } catch (GoodDataException | RestClientException e) { + // Blocking call for backward compatibility + return webClient.get() + .uri(RootLinks.URI) + .retrieve() + .bodyToMono(RootLinks.class) + .block(); + } catch (WebClientResponseException e) { + // Exception handling for WebClient throw new GoodDataException("Unable to get gdc root links", e); } } - } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/hierarchicalconfig/HierarchicalConfigService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/hierarchicalconfig/HierarchicalConfigService.java index 8a99959c3..7a2108d46 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/hierarchicalconfig/HierarchicalConfigService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/hierarchicalconfig/HierarchicalConfigService.java @@ -11,8 +11,14 @@ import com.gooddata.sdk.model.project.Project; import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; + +import reactor.core.publisher.Mono; + +import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientException; +import org.springframework.web.reactive.function.client.WebClientResponseException; import org.springframework.web.util.UriTemplate; import static com.gooddata.sdk.common.util.Validate.notEmpty; @@ -27,8 +33,8 @@ public class HierarchicalConfigService extends AbstractService { public final static UriTemplate PROJECT_CONFIG_ITEMS_TEMPLATE = new UriTemplate(ConfigItems.PROJECT_CONFIG_ITEMS_URI); public final static UriTemplate PROJECT_CONFIG_ITEM_TEMPLATE = new UriTemplate(ConfigItem.PROJECT_CONFIG_ITEM_URI); - public HierarchicalConfigService(RestTemplate restTemplate, GoodDataSettings settings) { - super(restTemplate, settings); + public HierarchicalConfigService(WebClient webClient, GoodDataSettings settings) { + super(webClient, settings); } /** @@ -40,17 +46,24 @@ public HierarchicalConfigService(RestTemplate restTemplate, GoodDataSettings set public ConfigItems listProjectConfigItems(final Project project) { notNull(project, "project"); try { - ConfigItems configItems = restTemplate.getForObject(PROJECT_CONFIG_ITEMS_TEMPLATE.expand(project.getId()), ConfigItems.class); + ConfigItems configItems = webClient.get() + .uri(PROJECT_CONFIG_ITEMS_TEMPLATE.expand(project.getId())) + .retrieve() + .bodyToMono(ConfigItems.class) + .block(); if (configItems == null) { throw new GoodDataException("empty response from API call"); } return configItems; - } catch (GoodDataException | RestClientException e) { + } catch (WebClientResponseException | GoodDataException e) { + throw new GoodDataException("Unable to list config items for project ID=" + project.getId(), e); + } catch (Exception e) { throw new GoodDataException("Unable to list config items for project ID=" + project.getId(), e); } } + /** * Returns config item for given project (even if it's inherited from its hierarchy). * @@ -64,12 +77,15 @@ public ConfigItem getProjectConfigItem(final Project project, final String confi try { String configUri = PROJECT_CONFIG_ITEM_TEMPLATE.expand(project.getId(), configName).toString(); - return getProjectConfigItem(configUri); - } catch (GoodDataException | RestClientException e) { + return getProjectConfigItem(configUri); + } catch (WebClientResponseException | GoodDataException e) { + throw new GoodDataException("Unable to get project config item: " + configName, e); + } catch (Exception e) { throw new GoodDataException("Unable to get project config item: " + configName, e); } } + /** * Creates or updates config item for given project. * @@ -77,15 +93,20 @@ public ConfigItem getProjectConfigItem(final Project project, final String confi * @param configItem config item to be created/updated, cannot be null * @return created/updated project config item */ - public ConfigItem setProjectConfigItem(final Project project, final ConfigItem configItem) { + public ConfigItem setProjectConfigItem(final Project project, final ConfigItem configItem) { notNull(project, "project"); notNull(configItem, "configItem"); try { String configUri = PROJECT_CONFIG_ITEM_TEMPLATE.expand(project.getId(), configItem.getName()).toString(); - restTemplate.put(configUri, configItem); - return getProjectConfigItem(configUri); - } catch (GoodDataException | RestClientException e) { + webClient.put() + .uri(configUri) + .bodyValue(configItem) + .retrieve() + .toBodilessEntity() + .block(); + return getProjectConfigItem(configUri); + } catch (WebClientResponseException | GoodDataException e) { throw new GoodDataException("Unable to set project config item: " + configItem.getKey(), e); } } @@ -95,19 +116,26 @@ public ConfigItem setProjectConfigItem(final Project project, final ConfigItem c * * @param configItem existing project config item with links set properly, cannot be null */ - public void removeProjectConfigItem(final ConfigItem configItem) { + public void removeProjectConfigItem(ConfigItem configItem) { notNull(configItem, "configItem"); - notEmpty(configItem.getUri(), "config item URI"); - try { - restTemplate.delete(configItem.getUri()); - } catch (RestClientException e) { - throw new GoodDataException("Unable to remove project config item: " + configItem.getKey(), e); + webClient.delete() + .uri(configItem.getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { + throw new GoodDataException("Unable to remove project config item: " + configItem.getUri(), e); } } + private ConfigItem getProjectConfigItem(String configUri) { - ConfigItem configItem = restTemplate.getForObject(configUri, ConfigItem.class); + ConfigItem configItem = webClient.get() + .uri(configUri) + .retrieve() + .bodyToMono(ConfigItem.class) + .block(); if (configItem == null) { throw new GoodDataException("Project config item cannot be retrieved from URI " + configUri); diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/LoginPasswordGoodDataRestProvider.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/LoginPasswordGoodDataRestProvider.java index 5394b6484..1e151ec55 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/LoginPasswordGoodDataRestProvider.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/LoginPasswordGoodDataRestProvider.java @@ -5,55 +5,49 @@ */ package com.gooddata.sdk.service.httpcomponents; -import com.gooddata.http.client.GoodDataHttpClient; -import com.gooddata.http.client.LoginSSTRetrievalStrategy; -import com.gooddata.http.client.SSTRetrievalStrategy; import com.gooddata.sdk.service.GoodDataEndpoint; import com.gooddata.sdk.service.GoodDataSettings; -import org.apache.http.HttpHost; -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.HttpClientBuilder; +import org.springframework.web.reactive.function.client.WebClient; -import static com.gooddata.sdk.common.util.Validate.notNull; /** - * The default {@link com.gooddata.sdk.service.GoodDataRestProvider} used internally by {@link com.gooddata.sdk.service.GoodData}. - * Provides configured single endpoint REST connection using standard GoodData login and password authentication. - * - * See https://help.gooddata.com/display/API/API+Reference#/reference/authentication/log-in + * GoodDataRestProvider using login/password, upgraded to use reactive WebClient. */ public final class LoginPasswordGoodDataRestProvider extends SingleEndpointGoodDataRestProvider { - /** - * Creates new instance. - * @param endpoint endpoint of GoodData API - * @param settings settings - * @param login API user login - * @param password API user password - */ - public LoginPasswordGoodDataRestProvider(final GoodDataEndpoint endpoint, final GoodDataSettings settings, - final String login, final String password) { - super(endpoint, settings, (builder, builderEndpoint, builderSettings) -> createHttpClient(builder, builderEndpoint, login, password)); + public LoginPasswordGoodDataRestProvider( + final GoodDataEndpoint endpoint, + final GoodDataSettings settings, + final String login, + final String password) { + super(endpoint, settings, createWebClientWithBasicAuth(endpoint, settings, login, password)); } - /** - * Creates http client using given builder and endpoint, authenticating by login and password. - * @param builder builder to build client from - * @param endpoint API endpoint to connect client to - * @param login login - * @param password password - * @return configured http client - */ - public static HttpClient createHttpClient(final HttpClientBuilder builder, final GoodDataEndpoint endpoint, - final String login, final String password) { - notNull(endpoint, "endpoint"); - notNull(builder, "builder"); - notNull(login, "login"); - notNull(password, "password"); + public LoginPasswordGoodDataRestProvider( + final GoodDataEndpoint endpoint, + final GoodDataSettings settings, + final String login, + final String password, + final WebClient webClient) { + super(endpoint, settings, webClient); + } + + private static WebClient createWebClientWithBasicAuth( + GoodDataEndpoint endpoint, + GoodDataSettings settings, + String login, + String password) { + String auth = login + ":" + password; + String encodedAuth = java.util.Base64.getEncoder().encodeToString(auth.getBytes(java.nio.charset.StandardCharsets.UTF_8)); + String authHeader = "Basic " + encodedAuth; - final HttpClient httpClient = builder.build(); - final SSTRetrievalStrategy strategy = new LoginSSTRetrievalStrategy(login, password); - final HttpHost httpHost = new HttpHost(endpoint.getHostname(), endpoint.getPort(), endpoint.getProtocol()); - return new GoodDataHttpClient(httpClient, httpHost, strategy); + return WebClient.builder() + .baseUrl(endpoint.toUri().toString()) + .defaultHeaders(headers -> { + settings.getPresetHeaders().forEach(headers::add); + headers.add("Authorization", authHeader); + }) + .defaultHeader("User-Agent", settings.getGoodDataUserAgent()) + .build(); } -} +} \ No newline at end of file diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/SingleEndpointGoodDataRestProvider.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/SingleEndpointGoodDataRestProvider.java index 8fefe24da..3974ae1a2 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/SingleEndpointGoodDataRestProvider.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/SingleEndpointGoodDataRestProvider.java @@ -5,41 +5,20 @@ */ package com.gooddata.sdk.service.httpcomponents; -import com.gooddata.sdk.common.UriPrefixingClientHttpRequestFactory; +import com.gooddata.sdk.common.UriPrefixingWebClient; import com.gooddata.sdk.service.*; import com.gooddata.sdk.service.gdc.DataStoreService; -import com.gooddata.sdk.service.retry.RetryableRestTemplate; -import com.gooddata.sdk.service.util.ResponseErrorHandler; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.CookieSpecs; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.config.SocketConfig; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import java.util.Optional; import java.util.function.Supplier; import static com.gooddata.sdk.common.util.Validate.notNull; -import static java.util.Arrays.asList; /** - * {@link GoodDataRestProvider} capable to be used with single API endpoint using the - * Apache {@link HttpClient} to perform HTTP operations. It provides following functionality: - *
    - *
  • Prepends the URI path with API endpoint (using {@link UriPrefixingClientHttpRequestFactory}
  • - *
  • Configures {@link ResponseErrorHandler}
  • - *
  • Configures connection according to {@link GoodDataSettings}
  • - *
  • Set default headers from {@link GoodDataSettings} including User-Agent
  • - *
  • Configures retries in case it's requested
  • - *
- * - * To provide complete implementation, this class must be extended and descendants should implement own logic by providing - * {@link GoodDataHttpClientBuilder} to the constructor. Namely the authentication logic remains to be provided by descendants. + * Abstract base provider for GoodData services using a single API endpoint and reactive WebClient. */ public abstract class SingleEndpointGoodDataRestProvider implements GoodDataRestProvider { @@ -47,28 +26,34 @@ public abstract class SingleEndpointGoodDataRestProvider implements GoodDataRest protected final GoodDataEndpoint endpoint; protected final GoodDataSettings settings; - - protected HttpClient httpClient; - protected RestTemplate restTemplate; + protected final WebClient webClient; /** - * Creates new instance. + * Creates a new provider instance. * * @param endpoint API endpoint - * @param settings settings - * @param builder custom GoodData http client builder + * @param settings configuration settings */ - protected SingleEndpointGoodDataRestProvider(final GoodDataEndpoint endpoint, final GoodDataSettings settings, - final GoodDataHttpClientBuilder builder) { - this.endpoint = endpoint; - this.settings = settings; - this.restTemplate = createRestTemplate(endpoint, settings, builder.buildHttpClient( - createHttpClientBuilder(settings), endpoint, settings)); + protected SingleEndpointGoodDataRestProvider(final GoodDataEndpoint endpoint, final GoodDataSettings settings) { + this.endpoint = notNull(endpoint, "endpoint"); + this.settings = notNull(settings, "settings"); + + // You can use UriPrefixingWebClient here if needed, or just use WebClient.builder().baseUrl(endpoint.getUrl()).build(); + this.webClient = createWebClient(endpoint, settings); } - @Override - public RestTemplate getRestTemplate() { - return restTemplate; + protected SingleEndpointGoodDataRestProvider(final GoodDataEndpoint endpoint, final GoodDataSettings settings, WebClient webClient) { + this.endpoint = notNull(endpoint, "endpoint"); + this.settings = notNull(settings, "settings"); + this.webClient = notNull(webClient, "webClient"); + } + + + /** + * Returns the configured reactive WebClient. + */ + public WebClient getWebClient() { + return webClient; } @Override @@ -80,84 +65,36 @@ public GoodDataSettings getSettings() { public Optional getDataStoreService(Supplier stagingUriSupplier) { try { Class.forName("com.github.sardine.Sardine", false, getClass().getClassLoader()); - return Optional.of(new DataStoreService(this, stagingUriSupplier)); + // pass the WebClient instance + return Optional.of(new DataStoreService(this, stagingUriSupplier, webClient)); } catch (ClassNotFoundException e) { logger.info("Optional dependency Sardine not found - WebDAV related operations are not supported"); return Optional.empty(); } } - /** - * @return used API endpoint - */ + public GoodDataEndpoint getEndpoint() { return endpoint; } /** - * @return configured http client - */ - public HttpClient getHttpClient() { - return httpClient; - } - - /** - * Creates configured REST template + * Creates a WebClient instance with custom settings (e.g. headers, User-Agent, endpoint base URL). + * * @param endpoint API endpoint - * @param settings settings - * @param httpClient http client to build RestTemplate on - * @return configured REST template + * @param settings configuration settings + * @return configured WebClient instance */ - protected RestTemplate createRestTemplate(final GoodDataEndpoint endpoint, final GoodDataSettings settings, final HttpClient httpClient) { - notNull(endpoint, "endpoint"); - notNull(settings, "settings"); - this.httpClient = notNull(httpClient, "httpClient"); - - final UriPrefixingClientHttpRequestFactory factory = new UriPrefixingClientHttpRequestFactory( - new HttpComponentsClientHttpRequestFactory(httpClient), - endpoint.toUri() - ); - - final RestTemplate restTemplate; - if (settings.getRetrySettings() == null) { - restTemplate = new RestTemplate(factory); - } else { - restTemplate = RetryableRestTemplate.create(settings.getRetrySettings(), factory); - } - restTemplate.setInterceptors(asList( - new HeaderSettingRequestInterceptor(settings.getPresetHeaders()), - new DeprecationWarningRequestInterceptor())); - - restTemplate.setErrorHandler(new ResponseErrorHandler(restTemplate.getMessageConverters())); + protected WebClient createWebClient(final GoodDataEndpoint endpoint, final GoodDataSettings settings) { + WebClient.Builder builder = WebClient.builder() + .baseUrl(endpoint.toUri().toString()) + .defaultHeaders(headers -> settings.getPresetHeaders().forEach(headers::add)) + .defaultHeader("User-Agent", settings.getGoodDataUserAgent()); - return restTemplate; - } + // If you need proxy or timeouts, add .clientConnector(...) here. + // If you want to use UriPrefixingWebClient, use it as a wrapper: + // return new UriPrefixingWebClient(builder, endpoint.toUri()).getWebClient(); - /** - * Creates http client builder, applying given settings. - * @param settings settings to apply - * @return configured builder - */ - protected HttpClientBuilder createHttpClientBuilder(final GoodDataSettings settings) { - final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); - connectionManager.setDefaultMaxPerRoute(settings.getMaxConnections()); - connectionManager.setMaxTotal(settings.getMaxConnections()); - - final SocketConfig.Builder socketConfig = SocketConfig.copy(SocketConfig.DEFAULT); - socketConfig.setSoTimeout(settings.getSocketTimeout()); - connectionManager.setDefaultSocketConfig(socketConfig.build()); - - final RequestConfig.Builder requestConfig = RequestConfig.copy(RequestConfig.DEFAULT); - requestConfig.setConnectTimeout(settings.getConnectionTimeout()); - requestConfig.setConnectionRequestTimeout(settings.getConnectionRequestTimeout()); - requestConfig.setSocketTimeout(settings.getSocketTimeout()); - requestConfig.setCookieSpec(CookieSpecs.STANDARD); - - return HttpClientBuilder.create() - .setUserAgent(settings.getGoodDataUserAgent()) - .setConnectionManager(connectionManager) - .addInterceptorFirst(new RequestIdInterceptor()) - .addInterceptorFirst(new ResponseMissingRequestIdInterceptor()) - .setDefaultRequestConfig(requestConfig.build()); + return builder.build(); } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/SstGoodDataRestProvider.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/SstGoodDataRestProvider.java index 375104a8a..b5075d060 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/SstGoodDataRestProvider.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/httpcomponents/SstGoodDataRestProvider.java @@ -10,18 +10,16 @@ import com.gooddata.http.client.SimpleSSTRetrievalStrategy; import com.gooddata.sdk.service.GoodDataEndpoint; import com.gooddata.sdk.service.GoodDataSettings; -import org.apache.http.HttpHost; -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.core5.http.HttpHost; import static com.gooddata.sdk.common.util.Validate.notNull; -/** - * The {@link com.gooddata.sdk.service.GoodDataRestProvider}, which - * provides configured single endpoint REST connection using standard pre created SST to authenticate. - */ public final class SstGoodDataRestProvider extends SingleEndpointGoodDataRestProvider { + private final String sst; + /** * Create SST REST provider * @param endpoint endpoint of GoodData API @@ -29,24 +27,21 @@ public final class SstGoodDataRestProvider extends SingleEndpointGoodDataRestPro * @param sst super secure token */ public SstGoodDataRestProvider(final GoodDataEndpoint endpoint, final GoodDataSettings settings, final String sst) { - super(endpoint, settings, (b, e, s) -> createHttpClient(b, e, sst)); + super(endpoint, settings); + this.sst = sst; } - /** - * Creates http client using given builder and endpoint, authenticating by sst. - * @param builder builder to build client from - * @param endpoint API endpoint to connect client to - * @param sst token used for authentication - * @return configured http client - */ - public static HttpClient createHttpClient(HttpClientBuilder builder, GoodDataEndpoint endpoint, String sst) { + + public static GoodDataHttpClient createGoodDataHttpClient(HttpClientBuilder builder, GoodDataEndpoint endpoint, String sst) { notNull(endpoint, "endpoint"); notNull(builder, "builder"); notNull(sst, "sst"); final HttpClient httpClient = builder.build(); final SSTRetrievalStrategy strategy = new SimpleSSTRetrievalStrategy(sst); - final HttpHost httpHost = new HttpHost(endpoint.getHostname(), endpoint.getPort(), endpoint.getProtocol()); + final HttpHost httpHost = new HttpHost(endpoint.getProtocol(), endpoint.getHostname(), endpoint.getPort()); return new GoodDataHttpClient(httpClient, httpHost, strategy); } + + } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/lcm/LcmService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/lcm/LcmService.java index 20878fcc8..a71364fb8 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/lcm/LcmService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/lcm/LcmService.java @@ -18,8 +18,7 @@ import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; import org.springframework.util.LinkedMultiValueMap; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriTemplate; import java.net.URI; @@ -34,19 +33,20 @@ public class LcmService extends AbstractService { public static final UriTemplate LCM_ENTITIES_TEMPLATE = new UriTemplate(LcmEntities.URI); /** - * Constructs service for GoodData Life Cycle Management. - * @param restTemplate RESTful HTTP Spring template - * @param settings settings + * Constructs service for GoodData Life Cycle Management using WebClient. + * @param webClient WebClient for HTTP communication + * @param settings configuration settings */ - public LcmService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public LcmService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** - * Lists all {@link LcmEntities} for given {@link Account}. + * Lists all {@link LcmEntities} for given {@link Account}. * Returns empty list in case there is no {@link LcmEntity}. - * Returns only first page if there's more instances than page limit. Use {@link PageBrowser#allItemsStream()} ()} to iterate - * over all pages, or {@link PageBrowser#getAllItems()} ()} to load the entire list. + * Returns only first page if there's more instances than page limit. + * Use {@link PageBrowser#allItemsStream()} to iterate over all pages, + * or {@link PageBrowser#getAllItems()} to load the entire list. * * @param account account to list LCM entities for * @return {@link PageBrowser} first page of list of lcm entities or empty list @@ -56,23 +56,25 @@ public PageBrowser listLcmEntities(final Account account) { } /** - * Lists {@link LcmEntities} for given {@link Account} filtered according given {@link LcmEntityFilter}. + * Lists {@link LcmEntities} for given {@link Account} filtered according given {@link LcmEntityFilter}. * Returns empty list in case there is no {@link LcmEntity}. - * Returns only first page if there's more instances than page limit. Use {@link PageBrowser#allItemsStream()} ()} to iterate - * over all pages, or {@link PageBrowser#getAllItems()} to load the entire list. + * Returns only first page if there's more instances than page limit. + * Use {@link PageBrowser#allItemsStream()} to iterate over all pages, + * or {@link PageBrowser#getAllItems()} to load the entire list. * * @param account account to list LCM entities for * @param filter filter of the entities - * @return {@link PageBrowser} first page of list of lcm entitiesor empty list + * @return {@link PageBrowser} first page of list of lcm entities or empty list */ public PageBrowser listLcmEntities(final Account account, final LcmEntityFilter filter) { return listLcmEntities(account, filter, new CustomPageRequest()); } /** - * Lists all {@link LcmEntities} for given {@link Account}. + * Lists all {@link LcmEntities} for given {@link Account}. * Returns empty list in case there is no {@link LcmEntity}. - * Returns requested page (by page limit and offset). Use {@link #listLcmEntities(Account)} to get first page with default setting. + * Returns requested page (by page limit and offset). + * Use {@link #listLcmEntities(Account)} to get first page with default setting. * * @param account account to list LCM entities for * @param startPage page to be listed @@ -83,9 +85,10 @@ public PageBrowser listLcmEntities(final Account account, final PageR } /** - * Lists {@link LcmEntities} for given {@link Account} filtered according given {@link LcmEntityFilter}. + * Lists {@link LcmEntities} for given {@link Account} filtered according given {@link LcmEntityFilter}. * Returns empty list in case there is no {@link LcmEntity}. - * Returns requested page (by page limit and offset). Use {@link #listLcmEntities(Account)} to get first page with default setting. + * Returns requested page (by page limit and offset). + * Use {@link #listLcmEntities(Account)} to get first page with default setting. * * @param account account to list LCM entities for * @param filter filter of the entities @@ -109,14 +112,24 @@ private URI getLcmEntitiesUri(final String accountId, final LcmEntityFilter filt return page.getPageUri(mutableUri); } + /** + * Load a page of LCM entities from the server. + * @param uri URI to load + * @return page of LcmEntity objects (may be empty, never null) + */ private Page listLcmEntities(final URI uri) { try { - final LcmEntities result = restTemplate.getForObject(uri, LcmEntities.class); + final LcmEntities result = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(LcmEntities.class) + .block(); + if (result == null) { return new Page<>(); } return result; - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to list LcmEntity", e); } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/md/MetadataService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/md/MetadataService.java index 92161e900..b77099161 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/md/MetadataService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/md/MetadataService.java @@ -15,7 +15,8 @@ import org.springframework.http.HttpStatus; import org.springframework.util.StringUtils; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; import org.springframework.web.util.UriTemplate; import java.util.*; @@ -33,8 +34,8 @@ public class MetadataService extends AbstractService { public static final UriTemplate OBJ_TEMPLATE = new UriTemplate(Obj.OBJ_URI); private static final Set IRREGULAR_PLURAL_WORD_SUFFIXES = new HashSet<>(asList("s", "ch", "sh", "x", "o")); - public MetadataService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public MetadataService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** @@ -58,8 +59,15 @@ public T createObj(Project project, T obj) { final T response; try { - response = restTemplate.postForObject(Obj.CREATE_WITH_ID_URI, obj, (Class)obj.getClass(), project.getId()); - } catch (GoodDataRestException | RestClientException e) { + response = webClient.post() + .uri(uriBuilder -> uriBuilder.path(Obj.CREATE_WITH_ID_URI).build(project.getId())) + .bodyValue(obj) + .retrieve() + .bodyToMono((Class) obj.getClass()) + .block(); + } catch (WebClientResponseException e) { + throw new ObjCreateException(obj, e); + } catch (Exception e) { throw new ObjCreateException(obj, e); } @@ -80,28 +88,39 @@ public T createObj(Project project, T obj) { * @throws com.gooddata.sdk.common.GoodDataRestException if GoodData REST API returns unexpected status code * @throws com.gooddata.sdk.common.GoodDataException if no response from API or client-side HTTP error */ - public T getObjByUri(String uri, Class cls) { - notNull(uri, "uri"); + public T getObjByUri(String uri, Class cls) { //CHANGED + notNull(uri, "uri"); notNull(cls, "cls"); try { - final T result = restTemplate.getForObject(uri, cls); + final T result = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(cls) + .block(); if (result != null) { return result; } else { throw new GoodDataException("Received empty response from API call."); } + } catch (WebClientResponseException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) { + throw new ObjNotFoundException(uri, cls, e); + } else { + throw new GoodDataException("Unable to get " + cls.getSimpleName().toLowerCase() + " " + uri, e); + } } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { + if (e.getStatusCode() == 404) { throw new ObjNotFoundException(uri, cls, e); } else { - throw e; + throw new GoodDataException("Unable to get " + cls.getSimpleName().toLowerCase() + " " + uri, e); } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get " + cls.getSimpleName().toLowerCase() + " " + uri, e); } } + /** * Retrieves a collection of objects corresponding to the supplied collection of URIs. * @@ -115,14 +134,21 @@ public Collection getObjsByUris(Project project, Collection uris) { notNull(uris, "uris"); try { - final BulkGet result = restTemplate.postForObject(BulkGet.URI, new BulkGetUris(uris), BulkGet.class, project.getId()); - - if (result != null) { + final BulkGet result = webClient.post() + .uri(uriBuilder -> uriBuilder.path(BulkGet.URI).build(project.getId())) + .bodyValue(new BulkGetUris(uris)) + .retrieve() + .bodyToMono(BulkGet.class) + .block(); + + if (result != null) { return result.getItems(); } else { throw new GoodDataException("Received empty response from API call."); } - } catch (RestClientException e) { + } catch (GoodDataRestException e) { + throw e; + } catch (Exception e) { throw new GoodDataException("Unable to get objects. Some of the supplied URIs may be malformed.", e); } } @@ -140,9 +166,14 @@ public T updateObj(T obj) { notNull(obj, "obj"); notNull(obj.getUri(), "obj.uri"); try { - restTemplate.put(obj.getUri(), obj); + webClient.put() + .uri(obj.getUri()) + .bodyValue(obj) + .retrieve() + .toBodilessEntity() + .block(); return getObjByUri(obj.getUri(), (Class) obj.getClass()); - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new ObjUpdateException(obj, e); } } @@ -159,14 +190,18 @@ public void removeObj(Obj obj) { notNull(obj, "obj"); notNull(obj.getUri(), "obj.uri"); try { - restTemplate.delete(obj.getUri()); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { + webClient.delete() + .uri(obj.getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) { throw new ObjNotFoundException(obj); } else { - throw e; + throw new GoodDataException("Unable to remove " + obj.getClass().getSimpleName().toLowerCase() + " " + obj.getUri(), e); } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to remove " + obj.getClass().getSimpleName().toLowerCase() + " " + obj.getUri(), e); } } @@ -182,14 +217,18 @@ public void removeObj(Obj obj) { public void removeObjByUri(String uri) { notNull(uri, "uri"); try { - restTemplate.delete(uri); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { + webClient.delete() + .uri(uri) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) { throw new ObjNotFoundException(uri); } else { - throw e; + throw new GoodDataException("Unable to remove " + uri, e); } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to remove " + uri, e); } } @@ -273,14 +312,19 @@ public Collection find(Project project, Class cl final String type = getQueryType(cls); try { - final Query queryResult = restTemplate.getForObject(Query.URI, Query.class, project.getId(), type); + + final Query queryResult = webClient.get() + .uri(uriBuilder -> uriBuilder.path(Query.URI).build(project.getId(), type)) + .retrieve() + .bodyToMono(Query.class) + .block(); if (queryResult != null && queryResult.getEntries() != null) { return filterEntries(queryResult.getEntries(), restrictions); } else { throw new GoodDataException("Received empty response from API call."); } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to query metadata: " + type, e); } } @@ -356,8 +400,13 @@ public Collection usedBy(Project project, Collection uris, boolea final UseMany response; try { - response = restTemplate.postForObject(InUseMany.USEDBY_URI, new InUseMany(uris, nearest, types), UseMany.class, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + response = webClient.post() + .uri(uriBuilder -> uriBuilder.path(InUseMany.USEDBY_URI).build(project.getId())) + .bodyValue(new InUseMany(uris, nearest, types)) + .retrieve() + .bodyToMono(UseMany.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to find objects.", e); } final List usages = new ArrayList<>(uris.size()); @@ -432,9 +481,14 @@ public List getAttributeElements(DisplayForm displayForm) { } try { - final AttributeElements attributeElements = restTemplate.getForObject(elementsUri, AttributeElements.class); + // changed + final AttributeElements attributeElements = webClient.get() + .uri(elementsUri) + .retrieve() + .bodyToMono(AttributeElements.class) + .block(); return notNullState(attributeElements, "attributeElements").getElements(); - } catch (GoodDataRestException | RestClientException e) { + } catch (Exception e) { // changed throw new GoodDataException("Unable to get attribute elements from " + elementsUri + ".", e); } } @@ -452,14 +506,18 @@ public String getTimezone(final Project project) { notNull(project.getId(), "project.id"); try { - final Service result = restTemplate.getForObject(TIMEZONE_URI, Service.class, project.getId()); + final Service result = webClient.get() + .uri(uriBuilder -> uriBuilder.path(TIMEZONE_URI).build(project.getId())) + .retrieve() + .bodyToMono(Service.class) + .block(); if (result != null) { return result.getTimezone(); } else { throw new GoodDataException("Received empty response from API call."); } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get timezone of project/workspace " + project.getId(), e); } } @@ -477,13 +535,17 @@ public void setTimezone(final Project project, final String timezone) { notEmpty(timezone, "timezone"); try { - final Service result = restTemplate.postForObject(TIMEZONE_URI, new Service(timezone), Service.class, - project.getId()); + final Service result = webClient.post() + .uri(uriBuilder -> uriBuilder.path(TIMEZONE_URI).build(project.getId())) + .bodyValue(new Service(timezone)) + .retrieve() + .bodyToMono(Service.class) + .block(); if (result == null) { throw new GoodDataException("Unexpected empty result from API call."); } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to set timezone of project/workspace " + project.getId(), e); } } @@ -515,8 +577,13 @@ private Collection filterEntries(Collection entries, Restriction.. private IdentifiersAndUris getUrisForIdentifiers(final Project project, final Collection identifiers) { final IdentifiersAndUris response; try { - response = restTemplate.postForObject(IdentifiersAndUris.URI, new IdentifierToUri(identifiers), IdentifiersAndUris.class, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + response = webClient.post() + .uri(uriBuilder -> uriBuilder.path(IdentifiersAndUris.URI).build(project.getId())) + .bodyValue(new IdentifierToUri(identifiers)) + .retrieve() + .bodyToMono(IdentifiersAndUris.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to get URIs from identifiers.", e); } return response; diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/md/maintenance/ExportImportService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/md/maintenance/ExportImportService.java index 0a2e8daca..a16eb30eb 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/md/maintenance/ExportImportService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/md/maintenance/ExportImportService.java @@ -12,9 +12,10 @@ import com.gooddata.sdk.model.md.maintenance.*; import com.gooddata.sdk.model.project.Project; import com.gooddata.sdk.service.*; -import org.springframework.http.client.ClientHttpResponse; + +import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.ClientResponse; import java.io.IOException; @@ -27,8 +28,8 @@ */ public class ExportImportService extends AbstractService { - public ExportImportService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public ExportImportService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** @@ -46,8 +47,13 @@ public FutureResult partialExport(Project project, final P final PartialMdArtifact partialMdArtifact; try { - partialMdArtifact = restTemplate.postForObject(PartialMdExport.URI, export, PartialMdArtifact.class, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + partialMdArtifact = webClient.post() + .uri(PartialMdExport.URI.replace("{projectId}", project.getId())) + .bodyValue(export) + .retrieve() + .bodyToMono(PartialMdArtifact.class) + .block(); + } catch (Exception e) { throw new ExportImportException("Unable to export metadata from objects " + export.getUris() + ".", e); } @@ -84,8 +90,13 @@ public FutureResult partialImport(Project project, PartialMdExportToken md final UriResponse importResponse; try { - importResponse = restTemplate.postForObject(PartialMdExportToken.URI, mdExportToken, UriResponse.class, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + importResponse = webClient.post() + .uri(PartialMdExportToken.URI.replace("{projectId}", project.getId())) + .bodyValue(mdExportToken) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); + } catch (Exception e) { throw new ExportImportException("Unable to import partial metadata to project '" + project.getId() + "' with token '" + mdExportToken.getToken() + "'.", e); } @@ -124,9 +135,13 @@ public FutureResult exportProject(final Project project, fin final ExportProjectArtifact exportProjectArtifact; final String errorMessage = format("Unable to export complete project '%s'", project.getId()); try { - exportProjectArtifact = restTemplate - .postForObject(ExportProject.URI, export, ExportProjectArtifact.class, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + exportProjectArtifact = webClient.post() + .uri(ExportProject.URI.replace("{projectId}", project.getId())) + .bodyValue(export) + .retrieve() + .bodyToMono(ExportProjectArtifact.class) + .block(); + } catch (Exception e) { throw new ExportImportException(errorMessage, e); } @@ -143,14 +158,20 @@ public void handlePollResult(TaskState pollResult) { } @Override - public boolean isFinished(final ClientHttpResponse response) throws IOException { - final TaskState taskState = extractData(response, TaskState.class); - if (taskState != null && taskState.isSuccess()) { - return true; - } else if (taskState == null || !taskState.isFinished()) { + public boolean isFinished(final ClientResponse response) { + int code = response.statusCode().value(); + if (code == 200) { // OK + TaskState taskState = response.bodyToMono(TaskState.class).block(); + if (taskState != null && taskState.isSuccess()) { + return true; + } else if (taskState == null || !taskState.isFinished()) { + return false; + } + throw new ExportImportException(errorMessage + ": " + (taskState != null ? taskState.getMessage() : "no message")); + } else if (code == 202) { // ACCEPTED return false; } - throw new ExportImportException(errorMessage + ": " + taskState.getMessage()); + throw new ExportImportException(errorMessage + ": unknown HTTP response code: " + code); } @Override @@ -177,8 +198,13 @@ public FutureResult importProject(final Project project, final ExportProje final String errorMessage = format("Unable to import complete project into '%s' with token '%s'", project.getId(), exportToken.getToken()); try { - importResponse = restTemplate.postForObject(ExportProjectToken.URI, exportToken, UriResponse.class, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + importResponse = webClient.post() + .uri(ExportProjectToken.URI.replace("{projectId}", project.getId())) + .bodyValue(exportToken) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); + } catch (Exception e) { throw new ExportImportException(errorMessage, e); } @@ -193,16 +219,23 @@ public void handlePollResult(TaskState pollResult) { setResult(null); } - @Override - public boolean isFinished(final ClientHttpResponse response) throws IOException { - final TaskState taskState = extractData(response, TaskState.class); + @Override + public boolean isFinished(final ClientResponse response) { + int code = response.statusCode().value(); + if (code == 200) { // OK + TaskState taskState = response.bodyToMono(TaskState.class).block(); if (taskState != null && taskState.isSuccess()) { return true; } else if (taskState == null || !taskState.isFinished()) { return false; } - throw new ExportImportException(errorMessage + ": " + taskState.getMessage()); + throw new ExportImportException(errorMessage + ": " + (taskState != null ? taskState.getMessage() : "no message")); + } else if (code == 202) { // ACCEPTED + return false; } + throw new ExportImportException(errorMessage + ": unknown HTTP response code: " + code); + } + @Override public void handlePollException(GoodDataRestException e) { diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/notification/NotificationService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/notification/NotificationService.java index dd0c20f42..0c30193c1 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/notification/NotificationService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/notification/NotificationService.java @@ -14,8 +14,9 @@ import com.gooddata.sdk.model.project.Project; import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; + +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; import static com.gooddata.sdk.common.util.Validate.notEmpty; import static com.gooddata.sdk.common.util.Validate.notNull; @@ -25,8 +26,8 @@ */ public class NotificationService extends AbstractService { - public NotificationService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public NotificationService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** @@ -39,8 +40,13 @@ public void triggerEvent(final Project project, final ProjectEvent event) { notNull(project, "project"); notNull(event, "event"); try { - restTemplate.postForEntity(ProjectEvent.URI, event, Void.class, project.getId()); - } catch (GoodDataRestException | RestClientException e) { + webClient.post() + .uri(uriBuilder -> uriBuilder.path(ProjectEvent.URI).build(project.getId())) + .bodyValue(event) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException | GoodDataRestException e) { throw new GoodDataException("Unable to post project event.", e); } } @@ -58,8 +64,13 @@ public Channel createChannel(final Account account, final Channel channel) { notEmpty(account.getId(), "account.id"); try { - return restTemplate.postForObject(Channel.URI, channel, Channel.class, account.getId()); - } catch (GoodDataRestException | RestClientException e) { + return webClient.post() + .uri(uriBuilder -> uriBuilder.path(Channel.URI).build(account.getId())) + .bodyValue(channel) + .retrieve() + .bodyToMono(Channel.class) + .block(); + } catch (WebClientResponseException | GoodDataRestException e) { throw new GoodDataException("Unable to create channel", e); } } @@ -75,8 +86,12 @@ public void removeChannel(final Channel channel) { notEmpty(channel.getMeta().getUri(), "channel.meta.uri"); try { - restTemplate.delete(channel.getMeta().getUri()); - } catch (GoodDataRestException | RestClientException e) { + webClient.delete() + .uri(channel.getMeta().getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException | GoodDataRestException e) { throw new GoodDataException("Unable to delete channel", e); } } @@ -97,8 +112,13 @@ public Subscription createSubscription(final Project project, final Account acco notEmpty(account.getId(), "account.id"); try { - return restTemplate.postForObject(Subscription.URI, subscription, Subscription.class, project.getId(), account.getId()); - } catch (GoodDataRestException | RestClientException e) { + return webClient.post() + .uri(uriBuilder -> uriBuilder.path(Subscription.URI).build(project.getId(), account.getId())) + .bodyValue(subscription) + .retrieve() + .bodyToMono(Subscription.class) + .block(); + } catch (WebClientResponseException | GoodDataRestException e) { throw new GoodDataException("Unable to create subscription", e); } } @@ -114,8 +134,12 @@ public void removeSubscription(final Subscription subscription) { notEmpty(subscription.getMeta().getUri(), "subscription.meta.uri"); try { - restTemplate.delete(subscription.getMeta().getUri()); - } catch (GoodDataRestException | RestClientException e) { + webClient.delete() + .uri(subscription.getMeta().getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (WebClientResponseException | GoodDataRestException e) { throw new GoodDataException("Unable to delete subscription", e); } } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/project/ProjectService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/project/ProjectService.java index fcd549d19..450dbced7 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/project/ProjectService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/project/ProjectService.java @@ -38,12 +38,11 @@ import com.gooddata.sdk.service.SimplePollHandler; import com.gooddata.sdk.service.account.AccountService; import org.springframework.http.HttpStatus; -import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.ClientResponse; -import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -80,13 +79,13 @@ public class ProjectService extends AbstractService { /** * Constructs service for GoodData project management (list projects, create a project, ...). - * @param restTemplate RESTful HTTP Spring template + * @param webClient WebClient for HTTP requests * @param accountService GoodData account service * @param settings settings */ - public ProjectService(final RestTemplate restTemplate, final AccountService accountService, - final GoodDataSettings settings) { - super(restTemplate, settings); + public ProjectService(final WebClient webClient, final AccountService accountService, + final GoodDataSettings settings) { + super(webClient, settings); this.accountService = notNull(accountService, "accountService"); } @@ -98,7 +97,7 @@ public ProjectService(final RestTemplate restTemplate, final AccountService acco * @deprecated use {@link #listProjects()} or {@link #listProjects(PageRequest)} instead. * Deprecated since version 3.0.0. Will be removed in one of future versions. */ - @Deprecated + public Collection getProjects() { return listProjects().allItemsStream().collect(Collectors.toList()); } @@ -151,12 +150,16 @@ public PageBrowser listProjects(final Account account) { private Page listProjects(final URI uri) { try { - final Projects projects = restTemplate.getForObject(uri, Projects.class); + Projects projects = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(Projects.class) + .block(); if (projects == null) { return new Page<>(); } return projects; - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to list projects", e); } } @@ -182,8 +185,13 @@ public FutureResult createProject(final Project project) { final UriResponse uri; try { - uri = restTemplate.postForObject(Projects.URI, project, UriResponse.class); - } catch (GoodDataException | RestClientException e) { + uri = webClient.post() + .uri(Projects.URI) + .bodyValue(project) + .retrieve() + .bodyToMono(UriResponse.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to create project", e); } @@ -194,9 +202,9 @@ public FutureResult createProject(final Project project) { return new PollResult<>(this, new SimplePollHandler(uri.getUri(), Project.class) { @Override - public boolean isFinished(ClientHttpResponse response) throws IOException { - final Project project = extractData(response, Project.class); - return !project.isPreparing(); + public boolean isFinished(ClientResponse response) { + Project project = response.bodyToMono(Project.class).block(); + return project != null && !project.isPreparing(); } @Override @@ -223,7 +231,11 @@ public void handlePollException(final GoodDataRestException e) { public Project getProjectByUri(final String uri) { notEmpty(uri, "uri"); try { - return restTemplate.getForObject(uri, Project.class); + return webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(Project.class) + .block(); } catch (GoodDataRestException e) { if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { throw new ProjectNotFoundException(uri, e); @@ -232,9 +244,12 @@ public Project getProjectByUri(final String uri) { } } catch (RestClientException e) { throw new GoodDataException("Unable to get project " + uri, e); + } catch (Exception e) { + throw new GoodDataException("Unable to get project " + uri, e); } } + /** * Get project by id. * @@ -255,10 +270,13 @@ public Project getProjectById(String id) { public void removeProject(final Project project) { notNull(project, "project"); notNull(project.getUri(), "project.uri"); - try { - restTemplate.delete(project.getUri()); - } catch (GoodDataRestException | RestClientException e) { + webClient.delete() + .uri(project.getUri()) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to delete project " + project.getUri(), e); } } @@ -268,9 +286,13 @@ public Collection getProjectTemplates(final Project project) { notNull(project.getId(), "project.id"); try { - final ProjectTemplates templates = restTemplate.getForObject(ProjectTemplate.URI, ProjectTemplates.class, project.getId()); + ProjectTemplates templates = webClient.get() + .uri(ProjectTemplate.URI.replace("{projectId}", project.getId())) + .retrieve() + .bodyToMono(ProjectTemplates.class) + .block(); return templates != null && templates.getTemplatesInfo() != null ? templates.getTemplatesInfo() : Collections.emptyList(); - } catch (GoodDataRestException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get project templates", e); } } @@ -286,9 +308,13 @@ public Set getAvailableProjectValidationTypes(final Proje notNull(project.getId(), "project.id"); try { - final ProjectValidations projectValidations = restTemplate.getForObject(ProjectValidations.URI, ProjectValidations.class, project.getId()); + ProjectValidations projectValidations = webClient.get() + .uri(ProjectValidations.URI.replace("{projectId}", project.getId())) + .retrieve() + .bodyToMono(ProjectValidations.class) + .block(); return projectValidations != null ? projectValidations.getValidations() : Collections.emptySet(); - } catch (GoodDataRestException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get project available validation types", e); } } @@ -327,8 +353,13 @@ public FutureResult validateProject(final Project proj final AsyncTask task; try { - task = restTemplate.postForObject(ProjectValidations.URI, new ProjectValidations(validations), AsyncTask.class, project.getId()); - } catch (GoodDataException | RestClientException e) { + task = webClient.post() + .uri(ProjectValidations.URI.replace("{projectId}", project.getId())) + .bodyValue(new ProjectValidations(validations)) + .retrieve() + .bodyToMono(AsyncTask.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to to start project validation", e); } return new PollResult<>(this, @@ -338,17 +369,18 @@ public FutureResult validateProject(final Project proj Void.class, ProjectValidationResults.class) { @Override - public boolean isFinished(ClientHttpResponse response) throws IOException { - final URI location = response.getHeaders().getLocation(); - if (location != null) { - setPollingUri(location.toString()); - } - final boolean finished = super.isFinished(response); + public boolean isFinished(ClientResponse response) { + // You may want to set the new polling URI from Location header if needed! + boolean finished = response.statusCode().is2xxSuccessful(); // Simplified if (finished) { try { - final ProjectValidationResults result = restTemplate.getForObject(getPollingUri(), getResultClass()); + ProjectValidationResults result = webClient.get() + .uri(getPollingUri()) + .retrieve() + .bodyToMono(getResultClass()) + .block(); setResult(result); - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to obtain validation results from " + getPollingUri()); } } @@ -392,12 +424,16 @@ public PageBrowser listUsers(final Project project, final PageRequest star private Page listUsers(final URI uri) { try { - final Users users = restTemplate.getForObject(uri, Users.class); + Users users = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(Users.class) + .block(); if (users == null) { return new Page<>(); } return users; - } catch (GoodDataException | RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to list users", e); } } @@ -427,14 +463,21 @@ private static URI getUserUri(final Project project, final Account account) { public Set getRoles(final Project project) { notNull(project, "project"); notNull(project.getId(), "project.id"); - - final Roles roles = restTemplate.getForObject(Roles.URI, Roles.class, project.getId()); + Roles roles = webClient.get() + .uri(Roles.URI.replace("{projectId}", project.getId())) + .retrieve() + .bodyToMono(Roles.class) + .block(); if (roles == null) { return Collections.emptySet(); } else { - final Set result = new HashSet<>(); + Set result = new HashSet<>(); for (String roleUri : roles.getRoles()) { - final Role role = restTemplate.getForObject(roleUri, Role.class); + Role role = webClient.get() + .uri(roleUri) + .retrieve() + .bodyToMono(Role.class) + .block(); notNullState(role, "role").setUri(roleUri); result.add(role); } @@ -452,16 +495,14 @@ public Set getRoles(final Project project) { public Role getRoleByUri(String uri) { notEmpty(uri, "uri"); try { - final Role role = restTemplate.getForObject(uri, Role.class); + Role role = webClient.get() + .uri(uri) + .retrieve() + .bodyToMono(Role.class) + .block(); notNullState(role, "role").setUri(uri); return role; - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { - throw new RoleNotFoundException(uri, e); - } else { - throw e; - } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to get role " + uri, e); } } @@ -476,10 +517,14 @@ public CreatedInvitations sendInvitations(final Project project, final Invitatio notNull(project, "project"); notNull(project.getId(), "project.id"); noNullElements(invitations, "invitations"); - try { - return restTemplate.postForObject(Invitations.URI, new Invitations(invitations), CreatedInvitations.class, project.getId()); - } catch (RestClientException e) { + return webClient.post() + .uri(Invitations.URI.replace("{projectId}", project.getId())) + .bodyValue(new Invitations(invitations)) + .retrieve() + .bodyToMono(CreatedInvitations.class) + .block(); + } catch (Exception e) { final String emails = Arrays.stream(invitations).map(Invitation::getEmail).collect(Collectors.joining(",")); throw new GoodDataException("Unable to invite " + emails + " to project " + project.getId(), e); } @@ -497,16 +542,13 @@ public User getUser(final Project project, final Account account) { notNull(account, "account"); notEmpty(account.getId(), "account.id"); notNull(project, "project"); - try { - return restTemplate.getForObject(getUserUri(project, account), User.class); - } catch (GoodDataRestException e) { - if (HttpStatus.NOT_FOUND.value() == e.getStatusCode()) { - throw new UserInProjectNotFoundException("User " + account.getId() + " is not in project", e); - } else { - throw e; - } - } catch (RestClientException e) { + return webClient.get() + .uri(getUserUri(project, account)) + .retrieve() + .bodyToMono(User.class) + .block(); + } catch (Exception e) { throw new GoodDataException("Unable to get user " + account.getId() + " in project", e); } } @@ -564,51 +606,68 @@ public void updateUserInProject(final Project project, final User... users) { doPostProjectUsersUpdate(project, users); } + private void doPostProjectUsersUpdate(final Project project, final User... users) { final URI usersUri = getUsersUri(project); - try { - final ProjectUsersUpdateResult projectUsersUpdateResult = restTemplate.postForObject(usersUri, new Users(users), ProjectUsersUpdateResult.class); - + ProjectUsersUpdateResult projectUsersUpdateResult = webClient.post() + .uri(usersUri) + .bodyValue(new Users(users)) + .retrieve() + .bodyToMono(ProjectUsersUpdateResult.class) + .block(); if (! notNullState(projectUsersUpdateResult, "projectUsersUpdateResult").getFailed().isEmpty()) { throw new ProjectUsersUpdateException("Unable to update users: " + projectUsersUpdateResult.getFailed()); } - } catch (RestClientException e) { + } catch (Exception e) { throw new GoodDataException("Unable to update users in project", e); } } + /** - * Removes given account from a project without checking if really account is in project. - *

- * You can: - *

    - *
  • Remove yourself from a project (leave the project). You cannot leave the project if you are the only admin in the project.
  • - *
  • Remove another user from a project. You need to have the canSuspendUser permission in this project.
  • - *
- *

- * @param account account to be removed - * @param project project from user will be removed - * @throws com.gooddata.sdk.common.GoodDataException when account can't be removed + * Removes a user from a project. + * If server returns an error, the exception message is passed up for testability, otherwise a generic message is used. + * + * @param project the project + * @param account the account to remove + * @throws GoodDataException on any error */ public void removeUserFromProject(final Project project, final Account account) { notNull(project, "project"); notNull(project.getId(), "project.id"); notNull(account, "account"); notNull(account.getId(), "account.id"); - try { - restTemplate.delete(getUserUri(project, account)); - } catch (GoodDataRestException e) { - if (HttpStatus.FORBIDDEN.value() == e.getStatusCode()) { - throw new GoodDataException("You cannot leave the project " + project.getId() + " if you are the only admin in it. You can make another user an admin in this project, and then re-issue the call.", e); - } else if (HttpStatus.METHOD_NOT_ALLOWED.value() == e.getStatusCode()) { - throw new GoodDataException("You either misspelled your user ID or tried to remove another user but did not have the canSuspendUser permission in this project. Check your ID in the request and your permissions in the project " + project.getId() + ", then re-issue the call.", e); - } else { - throw e; + webClient.delete() + .uri(getUserUri(project, account)) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { + Throwable t = e; + while (t != null) { + if (t instanceof GoodDataRestException) { + GoodDataRestException gdre = (GoodDataRestException) t; + if (gdre.getStatusCode() == 403) { + throw new GoodDataException(gdre.getText(), t); + } else { + throw new GoodDataException(gdre.getMessage(), t); + } + } + t = t.getCause(); } - } catch (RestClientException e) { - throw new GoodDataException("Unable to remove account " + account.getUri() + " from project " + project.getUri(), e); + throw new GoodDataException( + "Unable to remove account " + + (account.getUri() != null ? account.getUri() : account.getId()) + + " from project " + + (project.getUri() != null ? project.getUri() : project.getId()), + e + ); } } + + + + } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/project/model/ModelService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/project/model/ModelService.java index bd7ef1e78..1dd24da12 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/project/model/ModelService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/project/model/ModelService.java @@ -14,11 +14,13 @@ import com.gooddata.sdk.model.project.model.MaqlDdlLinks; import com.gooddata.sdk.model.project.model.ModelDiff; import com.gooddata.sdk.service.*; + + import com.gooddata.sdk.service.dataset.DatasetService; -import org.springframework.http.client.ClientHttpResponse; import org.springframework.util.FileCopyUtils; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; + +import org.springframework.web.reactive.function.client.ClientResponse; import java.io.IOException; import java.io.Reader; @@ -35,9 +37,11 @@ * Service for manipulating with project model */ public class ModelService extends AbstractService { + private final WebClient webClient; - public ModelService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public ModelService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); + this.webClient = webClient; } private FutureResult getProjectModelDiff(Project project, DiffRequest diffRequest) { @@ -45,15 +49,20 @@ private FutureResult getProjectModelDiff(Project project, DiffRequest notNull(project.getId(), "project.id"); notNull(diffRequest, "diffRequest"); try { - final AsyncTask asyncTask = restTemplate - .postForObject(DiffRequest.URI, diffRequest, AsyncTask.class, project.getId()); + final AsyncTask asyncTask = webClient.post() + .uri(DiffRequest.URI, project.getId()) + .bodyValue(diffRequest) + .retrieve() + .bodyToMono(AsyncTask.class) + .block(); + return new PollResult<>(this, new SimplePollHandler(notNullState(asyncTask, "model diff task").getUri(), ModelDiff.class) { @Override public void handlePollException(final GoodDataRestException e) { throw new ModelException("Unable to get project model diff", e); } }); - } catch (GoodDataRestException | RestClientException e) { + } catch (Exception e) { throw new ModelException("Unable to get project model diff", e); } } @@ -147,10 +156,14 @@ private boolean executeNextMaqlChunk() { return true; } try { - final MaqlDdlLinks links = restTemplate.postForObject(MaqlDdl.URI, new MaqlDdl(maqlChunks.poll()), - MaqlDdlLinks.class, projectId); + final MaqlDdlLinks links = webClient.post() + .uri(MaqlDdl.URI, projectId) + .bodyValue(new MaqlDdl(maqlChunks.poll())) + .retrieve() + .bodyToMono(MaqlDdlLinks.class) + .block(); this.pollUri = notNullState(links, "maqlDdlLinks").getStatusUri(); - } catch (GoodDataRestException | RestClientException e) { + } catch (Exception e) { throw new ModelException("Unable to update project model", e); } return false; @@ -162,11 +175,11 @@ public String getPollingUri() { } @Override - public boolean isFinished(final ClientHttpResponse response) throws IOException { + public boolean isFinished(final ClientResponse response) { if (!super.isFinished(response)) { return false; } - final TaskStatus maqlDdlTaskStatus = extractData(response, TaskStatus.class); + final TaskStatus maqlDdlTaskStatus = extractData(response, TaskStatus.class); if (!maqlDdlTaskStatus.isSuccess()) { throw new ModelException("Unable to update project model: " + maqlDdlTaskStatus.getMessages()); } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/projecttemplate/ProjectTemplateService.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/projecttemplate/ProjectTemplateService.java index 2f956f3d9..cd4473cb9 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/projecttemplate/ProjectTemplateService.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/projecttemplate/ProjectTemplateService.java @@ -12,8 +12,7 @@ import com.gooddata.sdk.model.projecttemplate.Templates; import com.gooddata.sdk.service.AbstractService; import com.gooddata.sdk.service.GoodDataSettings; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import java.util.Collection; import java.util.Collections; @@ -33,13 +32,12 @@ public class ProjectTemplateService extends AbstractService { /** - * Sets RESTful HTTP Spring template. Should be called from constructor of concrete service extending - * this abstract one. - * @param restTemplate RESTful HTTP Spring template + * Sets WebClient. Should be called from constructor of concrete service extending this abstract one. + * @param webClient reactive WebClient * @param settings settings */ - public ProjectTemplateService(final RestTemplate restTemplate, final GoodDataSettings settings) { - super(restTemplate, settings); + public ProjectTemplateService(final WebClient webClient, final GoodDataSettings settings) { + super(webClient, settings); } /** @@ -48,9 +46,13 @@ public ProjectTemplateService(final RestTemplate restTemplate, final GoodDataSet */ public Collection