From 0c5d1baf15fb5d4e41a55c717853df96c1c707d7 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 12 Dec 2022 18:46:45 +0000 Subject: [PATCH 01/74] Add model module from start.spring.io --- pom.xml | 1 + xapi-client/pom.xml | 35 ++++++++++++ .../dev/learning/xapi/client/StateParms.java | 28 +++++++++ .../dev/learning/xapi/client/XapiClient.java | 57 +++++++++++++++++++ .../src/main/resources/application.properties | 0 5 files changed, 121 insertions(+) create mode 100644 xapi-client/pom.xml create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/StateParms.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java create mode 100644 xapi-client/src/main/resources/application.properties diff --git a/pom.xml b/pom.xml index e834f2ba..847fc9ba 100644 --- a/pom.xml +++ b/pom.xml @@ -85,6 +85,7 @@ xapi-model + xapi-client diff --git a/xapi-client/pom.xml b/xapi-client/pom.xml new file mode 100644 index 00000000..f596edc4 --- /dev/null +++ b/xapi-client/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + dev.learning.xapi + xapi-build + 1.0.0-SNAPSHOT + + + xapi-client + + xAPI Client + learning.dev xAPI Client + + + + org.springframework.boot + spring-boot-starter-webflux + + + dev.learning.xapi + xapi-model + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateParms.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateParms.java new file mode 100644 index 00000000..83a0ef28 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateParms.java @@ -0,0 +1,28 @@ +package dev.learning.xapi.client; + +import java.net.URI; +import java.util.Optional; +import java.util.UUID; +import dev.learning.xapi.model.Agent; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.NonNull; +import lombok.Value; + +@Builder +@Value +public class StateParms { + + @NonNull + private URI activityId; + + @NonNull + private Agent agent; + + @NonNull + private String stateId; + + @Default + private Optional registration = Optional.empty(); + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java new file mode 100644 index 00000000..5e48d22f --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -0,0 +1,57 @@ +package dev.learning.xapi.client; + +import org.springframework.web.reactive.function.client.WebClient; +import dev.learning.xapi.model.ActivityState; + +/** + * Client for communicating with LRS or service which implements some of the xAPI communication + * resources. + * + * @author Thomas Turrell-Croft + * + * @see xAPI + * communication resources + */ +public class XapiClient { + + private final WebClient client; + + public XapiClient(WebClient.Builder builder) { + this.client = builder.baseUrl(" http://example.com/xAPI/").build(); + } + + /** + * Gets a state document + */ + public ActivityState getState(StateParms params) { + + // TODO Auto-generated method stub + + ActivityState activityState = client.get().uri(uriBuilder -> + + uriBuilder.path("activities/state") + + .queryParam("activityId", params.getActivityId()) + + .queryParam("agent", params.getAgent()) + + .queryParam("stateId", params.getStateId()) + + .queryParamIfPresent("deliveryDate", params.getRegistration()) + + .build()) + + .retrieve() + + .bodyToMono(ActivityState.class) + + .block(); + + return activityState; + + } + + + +} diff --git a/xapi-client/src/main/resources/application.properties b/xapi-client/src/main/resources/application.properties new file mode 100644 index 00000000..e69de29b From 6b41777681d62808fda5da57eb5590d9fe680231 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Wed, 11 Jan 2023 15:51:30 +0000 Subject: [PATCH 02/74] wip --- .../dev/learning/xapi/client/XapiClient.java | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 5e48d22f..94f17f1e 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -1,14 +1,13 @@ package dev.learning.xapi.client; -import org.springframework.web.reactive.function.client.WebClient; import dev.learning.xapi.model.ActivityState; +import org.springframework.web.reactive.function.client.WebClient; /** * Client for communicating with LRS or service which implements some of the xAPI communication * resources. * * @author Thomas Turrell-Croft - * * @see xAPI * communication resources @@ -22,25 +21,24 @@ public XapiClient(WebClient.Builder builder) { } /** - * Gets a state document + * Gets a state document. */ public ActivityState getState(StateParms params) { // TODO Auto-generated method stub - ActivityState activityState = client.get().uri(uriBuilder -> + final ActivityState activityState = client.get() + .uri(uriBuilder -> uriBuilder.path("activities/state") - uriBuilder.path("activities/state") + .queryParam("activityId", params.getActivityId()) - .queryParam("activityId", params.getActivityId()) + .queryParam("agent", params.getAgent()) - .queryParam("agent", params.getAgent()) + .queryParam("stateId", params.getStateId()) - .queryParam("stateId", params.getStateId()) + .queryParamIfPresent("deliveryDate", params.getRegistration()) - .queryParamIfPresent("deliveryDate", params.getRegistration()) - - .build()) + .build()) .retrieve() @@ -52,6 +50,4 @@ public ActivityState getState(StateParms params) { } - - } From fdddf02de3799581a9752e992ae350e18e36add6 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 16 Jan 2023 11:34:31 +0000 Subject: [PATCH 03/74] Update xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java --- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 94f17f1e..19d5233b 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -36,7 +36,7 @@ public ActivityState getState(StateParms params) { .queryParam("stateId", params.getStateId()) - .queryParamIfPresent("deliveryDate", params.getRegistration()) + .queryParamIfPresent("registration", params.getRegistration()) .build()) From 0351b136ccc5cee46b0c2aaf0613ac035c85baed Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 16 Jan 2023 15:02:32 +0000 Subject: [PATCH 04/74] fix pom (this change can be overridden) --- xapi-model/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-model/pom.xml b/xapi-model/pom.xml index f0294f5d..0f06fee0 100644 --- a/xapi-model/pom.xml +++ b/xapi-model/pom.xml @@ -4,7 +4,7 @@ dev.learning.xapi xapi-build - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT xapi-model From d5886bedb95d889185b7ca0bfef6af72f6c45298 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 16 Jan 2023 15:07:09 +0000 Subject: [PATCH 05/74] fix pom --- pom.xml | 4 ++-- xapi-client/pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 847fc9ba..881c0e79 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ dev.learning.xapi xapi-build - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT pom xAPI Build learning.dev xAPI Build @@ -278,7 +278,7 @@ dev.learning.xapi xapi-model - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT diff --git a/xapi-client/pom.xml b/xapi-client/pom.xml index f596edc4..14f0534b 100644 --- a/xapi-client/pom.xml +++ b/xapi-client/pom.xml @@ -4,7 +4,7 @@ dev.learning.xapi xapi-build - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT xapi-client From 2bb5d615314dc945997d0a9fc7c594cfea398e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 18 Jan 2023 10:29:03 +0000 Subject: [PATCH 06/74] working state endpoint requests --- .../xapi/client/DeleteStateRequest.java | 35 ++++++++ .../xapi/client/DeleteStatesRequest.java | 17 ++++ .../learning/xapi/client/GetStateRequest.java | 15 ++++ .../xapi/client/GetStatesRequest.java | 17 ++++ .../xapi/client/PostStateRequest.java | 35 ++++++++ .../learning/xapi/client/PutStateRequest.java | 13 +++ .../dev/learning/xapi/client/StateParms.java | 28 ------ .../learning/xapi/client/StateRequest.java | 24 +++++ .../learning/xapi/client/StatesRequest.java | 45 ++++++++++ .../dev/learning/xapi/client/XapiClient.java | 58 ++++++------- .../dev/learning/xapi/client/XapiRequest.java | 61 +++++++++++++ .../learning/xapi/client/StateRequestIT.java | 87 +++++++++++++++++++ .../dev/learning/xapi/client/TestApp.java | 31 +++++++ .../src/test/resources/application.properties | 1 + 14 files changed, 408 insertions(+), 59 deletions(-) create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java delete mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/StateParms.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java create mode 100644 xapi-client/src/test/resources/application.properties diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java new file mode 100644 index 00000000..7d3b5f08 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -0,0 +1,35 @@ +package dev.learning.xapi.client; + +import java.util.List; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.experimental.SuperBuilder; + +@SuperBuilder() +@Getter +@EqualsAndHashCode(callSuper=true) +public class DeleteStateRequest extends StateRequest{ + + private String match; + + private List noneMatch; + + protected void headers(HttpHeaders headers) { + if(match!=null) { + headers.set(HttpHeaders.IF_MATCH, match); + } + if(noneMatch !=null && !noneMatch.isEmpty()) { + headers.addAll(HttpHeaders.IF_NONE_MATCH, noneMatch); + } + } + + @Override + protected HttpMethod method() { + return HttpMethod.DELETE; + } + + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java new file mode 100644 index 00000000..1c2c3734 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -0,0 +1,17 @@ +package dev.learning.xapi.client; + +import org.springframework.http.HttpMethod; + +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@SuperBuilder() +@EqualsAndHashCode(callSuper=true) +public class DeleteStatesRequest extends StatesRequest{ + + @Override + protected HttpMethod method() { + return HttpMethod.DELETE; + } + + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java new file mode 100644 index 00000000..7270c2ce --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -0,0 +1,15 @@ +package dev.learning.xapi.client; + + +import org.springframework.http.HttpMethod; +import lombok.experimental.SuperBuilder; + +@SuperBuilder +public class GetStateRequest extends StateRequest{ + + @Override + protected HttpMethod method() { + return HttpMethod.GET; + } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java new file mode 100644 index 00000000..2d389233 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -0,0 +1,17 @@ +package dev.learning.xapi.client; + + +import java.util.List; + +import org.springframework.http.HttpMethod; +import lombok.experimental.SuperBuilder; + +@SuperBuilder +public class GetStatesRequest extends StatesRequest>{ + + @Override + protected HttpMethod method() { + return HttpMethod.GET; + } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java new file mode 100644 index 00000000..f0b826b5 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -0,0 +1,35 @@ +package dev.learning.xapi.client; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; + +import lombok.Builder.Default; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NonNull; +import lombok.experimental.SuperBuilder; + +@SuperBuilder() +@Getter +@EqualsAndHashCode(callSuper=true) +public class PostStateRequest extends DeleteStateRequest{ + + @NonNull + @Default + private String contentType = MediaType.APPLICATION_JSON_VALUE; + + @NonNull + private Object body; + + protected void headers(HttpHeaders headers) { + super.headers(headers); + headers.set(HttpHeaders.CONTENT_TYPE, contentType); + } + + @Override + protected HttpMethod method() { + return HttpMethod.POST; + } + + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java new file mode 100644 index 00000000..72a1a746 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -0,0 +1,13 @@ +package dev.learning.xapi.client; + +import org.springframework.http.HttpMethod; +import lombok.experimental.SuperBuilder; + +@SuperBuilder() +public class PutStateRequest extends PostStateRequest{ + + @Override + protected HttpMethod method() { + return HttpMethod.PUT; + } +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateParms.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateParms.java deleted file mode 100644 index 83a0ef28..00000000 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateParms.java +++ /dev/null @@ -1,28 +0,0 @@ -package dev.learning.xapi.client; - -import java.net.URI; -import java.util.Optional; -import java.util.UUID; -import dev.learning.xapi.model.Agent; -import lombok.Builder; -import lombok.Builder.Default; -import lombok.NonNull; -import lombok.Value; - -@Builder -@Value -public class StateParms { - - @NonNull - private URI activityId; - - @NonNull - private Agent agent; - - @NonNull - private String stateId; - - @Default - private Optional registration = Optional.empty(); - -} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java new file mode 100644 index 00000000..0194804b --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -0,0 +1,24 @@ +package dev.learning.xapi.client; + +import java.util.Map; + +import org.springframework.web.util.UriBuilder; + +import lombok.Getter; +import lombok.NonNull; +import lombok.experimental.SuperBuilder; + +@SuperBuilder +@Getter +abstract class StateRequest extends StatesRequest{ + + @NonNull + private String stateId; + + @Override + protected void query(UriBuilder uriBuilder, Map variableMap) { + super.query(uriBuilder, variableMap); + uriBuilder.queryParam("stateId", "{stateId}"); + variableMap.put("stateId", stateId); + } +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java new file mode 100644 index 00000000..24f9a958 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -0,0 +1,45 @@ +package dev.learning.xapi.client; + +import java.net.URI; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import org.springframework.web.util.UriBuilder; + +import lombok.Getter; +import lombok.NonNull; +import lombok.Builder.Default; +import lombok.experimental.SuperBuilder; + +@SuperBuilder +@Getter +abstract class StatesRequest extends XapiRequest{ + + @NonNull + private URI activityId; + + @NonNull + private String agent; + + @Default + private Optional registration = Optional.empty(); + + protected String path() { + return "activities/state"; + } + + @Override + protected void query(UriBuilder uriBuilder, Map variableMap) { + uriBuilder + + .queryParam("activityId", "{activityId}") + + .queryParam("agent", "{agent}") + + .queryParamIfPresent("registration", registration); + + variableMap.put("activityId", activityId); + variableMap.put("agent", agent); + } +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 19d5233b..b6fc90df 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -1,7 +1,13 @@ package dev.learning.xapi.client; -import dev.learning.xapi.model.ActivityState; +import reactor.core.publisher.Mono; + +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; + +import lombok.extern.slf4j.Slf4j; /** * Client for communicating with LRS or service which implements some of the xAPI communication @@ -12,42 +18,32 @@ * "https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#20-resources">xAPI * communication resources */ +@Slf4j public class XapiClient { private final WebClient client; public XapiClient(WebClient.Builder builder) { - this.client = builder.baseUrl(" http://example.com/xAPI/").build(); + this.client = builder + + .defaultHeader("X-Experience-API-Version", "1.0.3") + + .build(); } - /** - * Gets a state document. - */ - public ActivityState getState(StateParms params) { - - // TODO Auto-generated method stub - - final ActivityState activityState = client.get() - .uri(uriBuilder -> uriBuilder.path("activities/state") - - .queryParam("activityId", params.getActivityId()) - - .queryParam("agent", params.getAgent()) - - .queryParam("stateId", params.getStateId()) - - .queryParamIfPresent("registration", params.getRegistration()) - - .build()) - - .retrieve() - - .bodyToMono(ActivityState.class) - - .block(); - - return activityState; - + public ResponseEntity send(XapiRequest request) { + return request.execute(client) + + .onErrorResume(WebClientResponseException.class, + ex -> { + if(ex.getStatusCode().value() == 404) { + return Mono.just( new ResponseEntity(HttpStatusCode.valueOf(404))); + } + log.warn("Unsuccessful request: ", ex); + log.debug(ex.getResponseBodyAsString()); + return Mono.error(ex); + }) + + .block(); } - } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java new file mode 100644 index 00000000..e5bff378 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java @@ -0,0 +1,61 @@ +package dev.learning.xapi.client; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.core.GenericTypeResolver; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; +import org.springframework.web.util.UriBuilder; + +import lombok.RequiredArgsConstructor; +import lombok.experimental.SuperBuilder; +import reactor.core.publisher.Mono; + +@SuperBuilder() +@RequiredArgsConstructor +abstract class XapiRequest { + + @SuppressWarnings("unchecked") + Mono> execute(WebClient client) { + + RequestBodySpec r = client + + .method(method()) + + .uri(uriBuilder-> { + var variableMap = new HashMap(); + query(uriBuilder, variableMap); + return uriBuilder.path(path()).build(variableMap); + }) + + .headers(headers -> headers(headers)) + + ; + + var body = getBody(); + + if(body!=null) { + r.bodyValue(body); + } + + return r.retrieve().toEntity((Class) (GenericTypeResolver.resolveTypeArgument(getClass(), XapiRequest.class))); + + } + + protected void query(UriBuilder uribuilder, Map variableMap) {} + + protected void headers(HttpHeaders headers) {} + + protected abstract HttpMethod method(); + + protected abstract String path(); + + protected Object getBody() { + return null; + } + +} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java new file mode 100644 index 00000000..ff112fd9 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java @@ -0,0 +1,87 @@ +package dev.learning.xapi.client; + +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.net.URI; +import java.util.UUID; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; + + +@SpringBootTest(classes = TestApp.class) +public class StateRequestIT { + + @Autowired + private XapiClient client; + + @Test + public void t1 () { + + var activityId= URI.create("http://example.com"); + var agent ="{\"name\":\"q&qq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; + var stateId = UUID.randomUUID().toString(); + + var getRequest = GetStateRequest.builder() + .activityId(activityId).agent(agent).stateId(stateId).build(); + var response = client.send(getRequest); + + assertThat(response.getStatusCode().value(), is(404)); + } + + @Test + public void t2 () { + + var activityId= URI.create("http://example.com"); + var agent ="{\"name\":\"qqq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; + var stateId = UUID.randomUUID().toString(); + + var body = "qqq"; + var contentType = MediaType.TEXT_PLAIN_VALUE; + + var putRequest = PutStateRequest.builder() + .activityId(activityId).agent(agent).stateId(stateId).body(body).contentType(contentType).build(); + var putResponse = client.send(putRequest); + assertThat(putResponse.getStatusCode().value(), is(204)); + + var getRequest = GetStateRequest.builder() + .activityId(activityId).agent(agent).stateId(stateId).build(); + var response = client.send(getRequest); + + assertThat(response.getBody(), is(body)); + } + + @Test + public void t3 () { + + var activityId= URI.create("http://example.com/"+UUID.randomUUID()); + var agent ="{\"name\":\"qqq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; + var stateId1 = UUID.randomUUID().toString(); + var stateId2 = UUID.randomUUID().toString(); + + var body = "qqq"; + var contentType = MediaType.TEXT_PLAIN_VALUE; + + var putRequest1 = PutStateRequest.builder() + .activityId(activityId).agent(agent).stateId(stateId1).body(body).contentType(contentType).build(); + var putResponse1 = client.send(putRequest1); + assertThat(putResponse1.getStatusCode().value(), is(204)); + + var putRequest2 = PutStateRequest.builder() + .activityId(activityId).agent(agent).stateId(stateId2).body(body).contentType(contentType).build(); + var putResponse2 = client.send(putRequest2); + assertThat(putResponse2.getStatusCode().value(), is(204)); + + var getRequest = GetStatesRequest.builder() + .activityId(activityId).agent(agent).build(); + var response = client.send(getRequest); + + assertThat(response.getBody(), allOf(hasItem(stateId1),hasItem(stateId2))); + } + +} + + diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java new file mode 100644 index 00000000..3ad552f1 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java @@ -0,0 +1,31 @@ +package dev.learning.xapi.client; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpHeaders; +import org.springframework.util.Base64Utils; +import org.springframework.web.reactive.function.client.WebClient; + +@SpringBootConfiguration +@EnableAutoConfiguration +public class TestApp { + + @Value("${test.username:admin}") + String username; + + @Value("${test.password:password}") + String password; + + @Value("${test.url:http://localhost:8081/xapi/}") + String url; + + @Bean + public XapiClient xapiClient(WebClient.Builder webClientBuilder) { + return new XapiClient(webClientBuilder.baseUrl(url) + .defaultHeader(HttpHeaders.AUTHORIZATION, "basic "+ Base64Utils.encodeToString((username+":"+password) + .getBytes()))); + } + +} diff --git a/xapi-client/src/test/resources/application.properties b/xapi-client/src/test/resources/application.properties new file mode 100644 index 00000000..ae4d6668 --- /dev/null +++ b/xapi-client/src/test/resources/application.properties @@ -0,0 +1 @@ +logging.level.dev.learning.xapi = DEBUG From 1c95190b8db95d3c7514f21a2e9256778a69769d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 18 Jan 2023 12:38:22 +0000 Subject: [PATCH 07/74] add improvements - accept agent parameter as Actor object - add javadoc - add formatting --- .../xapi/client/DeleteStateRequest.java | 41 +++++--- .../xapi/client/DeleteStatesRequest.java | 21 ++-- .../learning/xapi/client/GetStateRequest.java | 15 ++- .../xapi/client/GetStatesRequest.java | 16 +++- .../xapi/client/PostStateRequest.java | 42 +++++--- .../learning/xapi/client/PutStateRequest.java | 14 ++- .../learning/xapi/client/StateRequest.java | 17 +++- .../learning/xapi/client/StatesRequest.java | 48 +++++++--- .../dev/learning/xapi/client/XapiClient.java | 96 +++++++++++++++---- .../dev/learning/xapi/client/XapiRequest.java | 86 ++++++++--------- .../learning/xapi/client/StateRequestIT.java | 12 ++- .../dev/learning/xapi/client/TestApp.java | 6 +- 12 files changed, 281 insertions(+), 133 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index 7d3b5f08..33d9d8c7 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -1,35 +1,48 @@ package dev.learning.xapi.client; import java.util.List; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; - import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.experimental.SuperBuilder; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +/** + * Request for deleting a single State document. + * + * @see Single + * State Document DELETE + * @author István Rátkai (Selindek) + */ @SuperBuilder() @Getter -@EqualsAndHashCode(callSuper=true) -public class DeleteStateRequest extends StateRequest{ +@EqualsAndHashCode(callSuper = true) +public class DeleteStateRequest extends StateRequest { - private String match; + /** + * The If-Match header of the request. + */ + private final String match; - private List noneMatch; + /** + * The If-None-Match headers of the request. + */ + private final List noneMatch; + @Override protected void headers(HttpHeaders headers) { - if(match!=null) { + if (match != null) { headers.set(HttpHeaders.IF_MATCH, match); } - if(noneMatch !=null && !noneMatch.isEmpty()) { + if (noneMatch != null && !noneMatch.isEmpty()) { headers.addAll(HttpHeaders.IF_NONE_MATCH, noneMatch); } } - + @Override - protected HttpMethod method() { + protected HttpMethod getMethod() { return HttpMethod.DELETE; } - - } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index 1c2c3734..4d615ec4 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -1,17 +1,24 @@ package dev.learning.xapi.client; -import org.springframework.http.HttpMethod; - import lombok.EqualsAndHashCode; import lombok.experimental.SuperBuilder; +import org.springframework.http.HttpMethod; +/** + * Request for deleting multiple State documents. + * + * @see Multiple + * State Document DELETE + * @author István Rátkai (Selindek) + */ @SuperBuilder() -@EqualsAndHashCode(callSuper=true) -public class DeleteStatesRequest extends StatesRequest{ +@EqualsAndHashCode(callSuper = true) +public class DeleteStatesRequest extends StatesRequest { @Override - protected HttpMethod method() { + protected HttpMethod getMethod() { return HttpMethod.DELETE; } - - } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index 7270c2ce..f1f9a5cc 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -1,14 +1,21 @@ package dev.learning.xapi.client; - -import org.springframework.http.HttpMethod; import lombok.experimental.SuperBuilder; +import org.springframework.http.HttpMethod; +/** + * Request for getting a single State document. + * + * @see Single + * State Document GET + * @author István Rátkai (Selindek) + */ @SuperBuilder -public class GetStateRequest extends StateRequest{ +public class GetStateRequest extends StateRequest { @Override - protected HttpMethod method() { + protected HttpMethod getMethod() { return HttpMethod.GET; } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index 2d389233..e9de05c0 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -1,16 +1,22 @@ package dev.learning.xapi.client; - import java.util.List; - -import org.springframework.http.HttpMethod; import lombok.experimental.SuperBuilder; +import org.springframework.http.HttpMethod; +/** + * Request for getting multiple State documents. + * + * @see Multiple + * State Document GET + * @author István Rátkai (Selindek) + */ @SuperBuilder -public class GetStatesRequest extends StatesRequest>{ +public class GetStatesRequest extends StatesRequest> { @Override - protected HttpMethod method() { + protected HttpMethod getMethod() { return HttpMethod.GET; } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index f0b826b5..7cd8db10 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -1,35 +1,53 @@ package dev.learning.xapi.client; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; - import lombok.Builder.Default; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +/** + * Request for posting a single State document. + * + * @see Single + * State Document POST + * @see JSON + * Procedure with Requirements + * @author István Rátkai (Selindek) + */ @SuperBuilder() @Getter -@EqualsAndHashCode(callSuper=true) -public class PostStateRequest extends DeleteStateRequest{ +@EqualsAndHashCode(callSuper = true) +public class PostStateRequest extends DeleteStateRequest { + /** + * The Content-Type header of the request. Default is + * application/json. + */ @NonNull @Default private String contentType = MediaType.APPLICATION_JSON_VALUE; - + + /** + * The body of the request. + */ @NonNull - private Object body; + private final Object body; + @Override protected void headers(HttpHeaders headers) { super.headers(headers); headers.set(HttpHeaders.CONTENT_TYPE, contentType); } - + @Override - protected HttpMethod method() { + protected HttpMethod getMethod() { return HttpMethod.POST; } - - } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index 72a1a746..fd6c64ab 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -1,13 +1,21 @@ package dev.learning.xapi.client; -import org.springframework.http.HttpMethod; import lombok.experimental.SuperBuilder; +import org.springframework.http.HttpMethod; +/** + * Request for putting a single State document. + * + * @see Single + * State Document PUT + * @author István Rátkai (Selindek) + */ @SuperBuilder() -public class PutStateRequest extends PostStateRequest{ +public class PutStateRequest extends PostStateRequest { @Override - protected HttpMethod method() { + protected HttpMethod getMethod() { return HttpMethod.PUT; } } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index 0194804b..647ffc74 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -1,19 +1,26 @@ package dev.learning.xapi.client; import java.util.Map; - -import org.springframework.web.util.UriBuilder; - import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; +import org.springframework.web.util.UriBuilder; +/** + * Abstract superclass for state requests manipulating a single state document. + * + * @author István Rátkai (Selindek) + * @param The response type of the request + */ @SuperBuilder @Getter -abstract class StateRequest extends StatesRequest{ +abstract class StateRequest extends StatesRequest { + /** + * The stateId query parameter. + */ @NonNull - private String stateId; + private final String stateId; @Override protected void query(UriBuilder uriBuilder, Map variableMap) { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 24f9a958..7127bb2a 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -1,44 +1,62 @@ package dev.learning.xapi.client; +import dev.learning.xapi.model.Actor; import java.net.URI; import java.util.Map; import java.util.Optional; import java.util.UUID; - -import org.springframework.web.util.UriBuilder; - +import lombok.Builder.Default; import lombok.Getter; import lombok.NonNull; -import lombok.Builder.Default; import lombok.experimental.SuperBuilder; +import org.springframework.web.util.UriBuilder; +/** + * Abstract superclass of xAPI state resource request. + * + * @see State + * Resource + * @author István Rátkai (Selindek) + * @param The response type of the request + */ @SuperBuilder @Getter -abstract class StatesRequest extends XapiRequest{ +abstract class StatesRequest extends XapiRequest { + /** + * The activityId query parameter. + */ @NonNull - private URI activityId; - + private final URI activityId; + + /** + * The agent query parameter. + */ @NonNull - private String agent; + private final Actor agent; + /** + * The optional registration query parameter. + */ @Default private Optional registration = Optional.empty(); - protected String path() { + @Override + protected String getPath() { return "activities/state"; } - + @Override protected void query(UriBuilder uriBuilder, Map variableMap) { uriBuilder - - .queryParam("activityId", "{activityId}") - .queryParam("agent", "{agent}") + .queryParam("activityId", "{activityId}") + + .queryParam("agent", "{agent}") + + .queryParamIfPresent("registration", registration); - .queryParamIfPresent("registration", registration); - variableMap.put("activityId", activityId); variableMap.put("agent", agent); } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index b6fc90df..e198920a 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -1,13 +1,17 @@ package dev.learning.xapi.client; -import reactor.core.publisher.Mono; - +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import dev.learning.xapi.model.Actor; +import java.util.HashMap; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.GenericTypeResolver; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; import org.springframework.web.reactive.function.client.WebClientResponseException; - -import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Mono; /** * Client for communicating with LRS or service which implements some of the xAPI communication @@ -22,28 +26,80 @@ public class XapiClient { private final WebClient client; + private final ObjectMapper objectMapper; - public XapiClient(WebClient.Builder builder) { + /** + * Default constructor for XapiClient. + * + * @param builder a {@link WebClient.Builder} object. The caller must set the baseUrl and the + * authorization header. + * @param objectMapper an {@link ObjectMapper}. It is used for converting {@link Actor} query + * parameters to JSON string during xAPI requests. + */ + public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { + this.objectMapper = objectMapper; this.client = builder - + .defaultHeader("X-Experience-API-Version", "1.0.3") - + .build(); } + /** + * Sends an xAPI request. + * + * @param The response type is defined by the request parameter. + * @param request an {@link XapiRequest} object describing the xAPI request. + * @return a {@link ResponseEntity} containing the response object defined by the request + * parameter. + */ + @SuppressWarnings("unchecked") public ResponseEntity send(XapiRequest request) { - return request.execute(client) - - .onErrorResume(WebClientResponseException.class, - ex -> { - if(ex.getStatusCode().value() == 404) { - return Mono.just( new ResponseEntity(HttpStatusCode.valueOf(404))); - } - log.warn("Unsuccessful request: ", ex); - log.debug(ex.getResponseBodyAsString()); - return Mono.error(ex); - }) - - .block(); + + final RequestBodySpec r = client + + .method(request.getMethod()) + + .uri(uriBuilder -> { + final var variableMap = new HashMap(); + request.query(uriBuilder, variableMap); + convertActors(variableMap); + return uriBuilder.path(request.getPath()).build(variableMap); + }) + + .headers(headers -> request.headers(headers)) + + ; + + final var body = request.getBody(); + + if (body != null) { + r.bodyValue(body); + } + + return r.retrieve().toEntity( + (Class) GenericTypeResolver.resolveTypeArgument(request.getClass(), XapiRequest.class)) + + .onErrorResume(WebClientResponseException.class, ex -> { + if (ex.getStatusCode().value() == 404) { + return Mono.just(new ResponseEntity(HttpStatusCode.valueOf(404))); + } + log.warn("Unsuccessful request: ", ex); + log.debug(ex.getResponseBodyAsString()); + return Mono.error(ex); + }) + + .block(); + } + + private void convertActors(HashMap variableMap) { + variableMap.entrySet().stream().filter(s -> s.getValue() instanceof Actor).forEach(s -> { + try { + s.setValue(objectMapper.writeValueAsString(s.getValue())); + } catch (final JsonProcessingException e) { + // Should not happen + } + }); + } } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java index e5bff378..990bf773 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java @@ -1,59 +1,59 @@ package dev.learning.xapi.client; -import java.util.HashMap; import java.util.Map; - -import org.springframework.core.GenericTypeResolver; +import lombok.RequiredArgsConstructor; +import lombok.experimental.SuperBuilder; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; import org.springframework.web.util.UriBuilder; -import lombok.RequiredArgsConstructor; -import lombok.experimental.SuperBuilder; -import reactor.core.publisher.Mono; - +/** + * Base class for xAPI request. + * + * @author István Rátkai (Selindek) + * @param The response type of the request + */ @SuperBuilder() @RequiredArgsConstructor abstract class XapiRequest { - - @SuppressWarnings("unchecked") - Mono> execute(WebClient client) { - - RequestBodySpec r = client - - .method(method()) - - .uri(uriBuilder-> { - var variableMap = new HashMap(); - query(uriBuilder, variableMap); - return uriBuilder.path(path()).build(variableMap); - }) - - .headers(headers -> headers(headers)) - - ; - - var body = getBody(); - - if(body!=null) { - r.bodyValue(body); - } - - return r.retrieve().toEntity((Class) (GenericTypeResolver.resolveTypeArgument(getClass(), XapiRequest.class))); + /** + * Callback method which sets the query parameters for the xAPI request. + * + * @param uribuilder an {@link UriBuilder} object. The methods add query templates to the + * builder. + * @param variableMap a {@link Map} containing the actual values for the query templates. + */ + protected void query(UriBuilder uribuilder, Map variableMap) { + } + + /** + * Callback method which sets the headers for the xAPI request. + * + * @param headers a {@link HttpHeaders} object. + */ + protected void headers(HttpHeaders headers) { } - protected void query(UriBuilder uribuilder, Map variableMap) {} - - protected void headers(HttpHeaders headers) {} - - protected abstract HttpMethod method(); - - protected abstract String path(); - + /** + * The request method. + * + * @return the request method as a {@link HttpMethod} object. + */ + protected abstract HttpMethod getMethod(); + + /** + * The path of the request endpoint. + * + * @return the path of the request endpoint as a String. + */ + protected abstract String getPath(); + + /** + * The request body. Default is null + * + * @return the request body. + */ protected Object getBody() { return null; } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java index ff112fd9..c81a8506 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java @@ -11,6 +11,8 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; +import dev.learning.xapi.model.Agent; + @SpringBootTest(classes = TestApp.class) public class StateRequestIT { @@ -22,7 +24,8 @@ public class StateRequestIT { public void t1 () { var activityId= URI.create("http://example.com"); - var agent ="{\"name\":\"q&qq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; + //var agent ="{\"name\":\"q&qq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; + var agent = Agent.builder().name("qqq&www").mbox("mailto:admin@launchlearning.io").build(); var stateId = UUID.randomUUID().toString(); var getRequest = GetStateRequest.builder() @@ -36,7 +39,8 @@ public void t1 () { public void t2 () { var activityId= URI.create("http://example.com"); - var agent ="{\"name\":\"qqq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; +// var agent ="{\"name\":\"qqq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; + var agent = Agent.builder().name("qqq&www").mbox("mailto:admin@launchlearning.io").build(); var stateId = UUID.randomUUID().toString(); var body = "qqq"; @@ -58,7 +62,9 @@ public void t2 () { public void t3 () { var activityId= URI.create("http://example.com/"+UUID.randomUUID()); - var agent ="{\"name\":\"qqq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; +// var agent ="{\"name\":\"qqq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; + var agent = Agent.builder().name("qqq&www").mbox("mailto:admin@launchlearning.io").build(); + var stateId1 = UUID.randomUUID().toString(); var stateId2 = UUID.randomUUID().toString(); diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java index 3ad552f1..7e95e0f9 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java @@ -8,6 +8,8 @@ import org.springframework.util.Base64Utils; import org.springframework.web.reactive.function.client.WebClient; +import com.fasterxml.jackson.databind.ObjectMapper; + @SpringBootConfiguration @EnableAutoConfiguration public class TestApp { @@ -22,10 +24,10 @@ public class TestApp { String url; @Bean - public XapiClient xapiClient(WebClient.Builder webClientBuilder) { + public XapiClient xapiClient(WebClient.Builder webClientBuilder, ObjectMapper objectMapper) { return new XapiClient(webClientBuilder.baseUrl(url) .defaultHeader(HttpHeaders.AUTHORIZATION, "basic "+ Base64Utils.encodeToString((username+":"+password) - .getBytes()))); + .getBytes())), objectMapper); } } From 82ec854876676dcc934691a1f9c547b4ec28ec1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 18 Jan 2023 12:38:22 +0000 Subject: [PATCH 08/74] add improvements - accept agent parameter as Actor object - add javadoc - add formatting From 2d3707a9c4331aa1ac28f18bbee4319e4c6b4a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 18 Jan 2023 15:28:17 +0000 Subject: [PATCH 09/74] more improvements - format tests - add type-safe method for getting a state - use MediaType for content-type header --- .../xapi/client/PostStateRequest.java | 4 +- .../dev/learning/xapi/client/XapiClient.java | 42 ++++- .../dev/learning/xapi/client/XapiRequest.java | 2 +- .../learning/xapi/client/StateRequestIT.java | 161 +++++++++++------- 4 files changed, 141 insertions(+), 68 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index 7cd8db10..b63de919 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -31,7 +31,7 @@ public class PostStateRequest extends DeleteStateRequest { */ @NonNull @Default - private String contentType = MediaType.APPLICATION_JSON_VALUE; + private MediaType contentType = MediaType.APPLICATION_JSON; /** * The body of the request. @@ -42,7 +42,7 @@ public class PostStateRequest extends DeleteStateRequest { @Override protected void headers(HttpHeaders headers) { super.headers(headers); - headers.set(HttpHeaders.CONTENT_TYPE, contentType); + headers.setContentType(contentType); } @Override diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index e198920a..92933368 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -48,13 +48,50 @@ public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { /** * Sends an xAPI request. * - * @param The response type is defined by the request parameter. + * @param The response type is defined by the request parameter. * @param request an {@link XapiRequest} object describing the xAPI request. * @return a {@link ResponseEntity} containing the response object defined by the request * parameter. */ @SuppressWarnings("unchecked") public ResponseEntity send(XapiRequest request) { + return _send(request, + (Class) GenericTypeResolver.resolveTypeArgument(request.getClass(), XapiRequest.class)); + } + + /** + *

+ * Convenient type-safe method for sending a {@link GetStateRequest} which expects an instance of + * a given JAVA class as a response. + *

+ *

+ * The {@link GetStateRequest} is the only xAPI request where the type of the response is not + * defined. Learning Record Providers can store ANY kind of data here. The type conversion of the + * returned state object happens based on the Content-Type header provided when + * the state was stored. If the stored state is incompatible with the + * Content-Type header or it cannot be converted to the expected response type + * then a {@link RuntimeException} is thrown. + *

+ *

+ * If the generic {@link XapiClient#send(XapiRequest)} method is used with {@link GetStateRequest} + * request then the state is returned a String. + *

+ * + * @param The response type is defined by the responseType parameter. + * @param request an {@link GetStateRequest} object. + * @param responseType a {@link Class} object defining the response type of the returning state. + * @return a {@link ResponseEntity} containing the response object . + * @see State + * Resources Description + * @throws RuntimeException when the returned state cannot be converted to the expected JAVA + * class. + */ + public ResponseEntity send(GetStateRequest request, Class responseType) { + return _send(request, responseType); + } + + private ResponseEntity _send(XapiRequest request, Class responseType) { final RequestBodySpec r = client @@ -77,8 +114,7 @@ public ResponseEntity send(XapiRequest request) { r.bodyValue(body); } - return r.retrieve().toEntity( - (Class) GenericTypeResolver.resolveTypeArgument(request.getClass(), XapiRequest.class)) + return r.retrieve().toEntity(responseType) .onErrorResume(WebClientResponseException.class, ex -> { if (ex.getStatusCode().value() == 404) { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java index 990bf773..f8fcd8f3 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java @@ -11,7 +11,7 @@ * Base class for xAPI request. * * @author István Rátkai (Selindek) - * @param The response type of the request + * @param The type of the response body. Can be {@link Void} for responses without body. */ @SuperBuilder() @RequiredArgsConstructor diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java index c81a8506..3461121a 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java @@ -1,93 +1,130 @@ package dev.learning.xapi.client; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import dev.learning.xapi.model.Actor; +import dev.learning.xapi.model.Agent; +import java.awt.Point; import java.net.URI; import java.util.UUID; - +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import dev.learning.xapi.model.Agent; - - @SpringBootTest(classes = TestApp.class) public class StateRequestIT { @Autowired private XapiClient client; - + + private URI activityId; + private Actor agent; + private String stateId; + private Object body; + private MediaType contentType; + + @BeforeEach + public void init() { + // set some default parameters + activityId = URI.create("http://learning.dev/" + UUID.randomUUID()); + agent = Agent.builder().name("admin").mbox("mailto:admin@learning.dev").build(); + stateId = UUID.randomUUID().toString(); + body = new Point(1, 2); + contentType = MediaType.APPLICATION_JSON; + } + + @Test + public void testGivenStateDoesNotExistWhenSendingGetStateRequestThenResponseStatusIsNotFound() { + + // Given State Does Not Exist + + // When Sending GetStateRequest + + final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) + .stateId(stateId).build(); + final var response = client.send(getRequest); + + // Then Response Status Is Not Found + + assertThat(response.getStatusCode(), is(HttpStatus.NOT_FOUND)); + } + @Test - public void t1 () { - - var activityId= URI.create("http://example.com"); - //var agent ="{\"name\":\"q&qq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; - var agent = Agent.builder().name("qqq&www").mbox("mailto:admin@launchlearning.io").build(); - var stateId = UUID.randomUUID().toString(); - - var getRequest = GetStateRequest.builder() - .activityId(activityId).agent(agent).stateId(stateId).build(); - var response = client.send(getRequest); - - assertThat(response.getStatusCode().value(), is(404)); + public void testGivenStateExistsWhenSendingGetStateRequestThenResponseBodyIsExpected() { + + // Given State Exists + body = "text body"; + contentType = MediaType.TEXT_PLAIN; + + final var putRequest = PutStateRequest.builder().activityId(activityId).agent(agent) + .stateId(stateId).body(body).contentType(contentType).build(); + final var putResponse = client.send(putRequest); + assertThat(putResponse.getStatusCode().value(), is(204)); + + // When Sending GetStateRequest + + final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) + .stateId(stateId).build(); + final var response = client.send(getRequest); + + // Then Response Body Is Expected + + assertThat(response.getBody(), is(body)); } - + @Test - public void t2 () { - - var activityId= URI.create("http://example.com"); -// var agent ="{\"name\":\"qqq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; - var agent = Agent.builder().name("qqq&www").mbox("mailto:admin@launchlearning.io").build(); - var stateId = UUID.randomUUID().toString(); - - var body = "qqq"; - var contentType = MediaType.TEXT_PLAIN_VALUE; - - var putRequest = PutStateRequest.builder() - .activityId(activityId).agent(agent).stateId(stateId).body(body).contentType(contentType).build(); - var putResponse = client.send(putRequest); + public void testGivenStateExistsWhenSendingTypedGetStateRequestThenResponseBodyIsExpected() { + + // Given State Exists + + final var putRequest = PutStateRequest.builder().activityId(activityId).agent(agent) + .stateId(stateId).body(body).contentType(contentType).build(); + final var putResponse = client.send(putRequest); assertThat(putResponse.getStatusCode().value(), is(204)); - var getRequest = GetStateRequest.builder() - .activityId(activityId).agent(agent).stateId(stateId).build(); - var response = client.send(getRequest); - + // When Sending Typed GetStateRequest + + final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) + .stateId(stateId).build(); + final var response = client.send(getRequest, Point.class); + + // Then Response Body Is Expected + assertThat(response.getBody(), is(body)); } - + @Test - public void t3 () { - - var activityId= URI.create("http://example.com/"+UUID.randomUUID()); -// var agent ="{\"name\":\"qqq\",\"mbox\":\"mailto:admin@launchlearning.io\"}"; - var agent = Agent.builder().name("qqq&www").mbox("mailto:admin@launchlearning.io").build(); - - var stateId1 = UUID.randomUUID().toString(); - var stateId2 = UUID.randomUUID().toString(); - - var body = "qqq"; - var contentType = MediaType.TEXT_PLAIN_VALUE; - - var putRequest1 = PutStateRequest.builder() - .activityId(activityId).agent(agent).stateId(stateId1).body(body).contentType(contentType).build(); - var putResponse1 = client.send(putRequest1); + public void testGivenMultipleStatesExistsWhenSendingGetStatesRequestThenResponseBodyIsExpected() { + + // Given Multiple States Exists + + final var stateId1 = UUID.randomUUID().toString(); + final var stateId2 = UUID.randomUUID().toString(); + + final var putRequest1 = PutStateRequest.builder().activityId(activityId).agent(agent) + .stateId(stateId1).body(body).contentType(contentType).build(); + final var putResponse1 = client.send(putRequest1); assertThat(putResponse1.getStatusCode().value(), is(204)); - var putRequest2 = PutStateRequest.builder() - .activityId(activityId).agent(agent).stateId(stateId2).body(body).contentType(contentType).build(); - var putResponse2 = client.send(putRequest2); + final var putRequest2 = PutStateRequest.builder().activityId(activityId).agent(agent) + .stateId(stateId2).body(body).contentType(contentType).build(); + final var putResponse2 = client.send(putRequest2); assertThat(putResponse2.getStatusCode().value(), is(204)); - var getRequest = GetStatesRequest.builder() - .activityId(activityId).agent(agent).build(); - var response = client.send(getRequest); - - assertThat(response.getBody(), allOf(hasItem(stateId1),hasItem(stateId2))); - } + // When Sending GetStatesRequest -} + final var getRequest = GetStatesRequest.builder().activityId(activityId).agent(agent).build(); + final var response = client.send(getRequest); + // Then Response Body Is Expected + assertThat(response.getBody(), allOf(hasItem(stateId1), hasItem(stateId2))); + } + +} From b42b7a0cac08b571995d4e7b9f300edf3e59b554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 18 Jan 2023 15:42:54 +0000 Subject: [PATCH 10/74] fix --- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 92933368..6aa10f72 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -74,7 +74,7 @@ public ResponseEntity send(XapiRequest request) { *

*

* If the generic {@link XapiClient#send(XapiRequest)} method is used with {@link GetStateRequest} - * request then the state is returned a String. + * request then the state is returned as a String. *

* * @param The response type is defined by the responseType parameter. From d94566becb2579ba65f0618127d1d0130342ad80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 18 Jan 2023 15:55:00 +0000 Subject: [PATCH 11/74] fix --- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 6aa10f72..dc7d8b6f 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -55,7 +55,7 @@ public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { */ @SuppressWarnings("unchecked") public ResponseEntity send(XapiRequest request) { - return _send(request, + return sendRequest(request, (Class) GenericTypeResolver.resolveTypeArgument(request.getClass(), XapiRequest.class)); } @@ -88,10 +88,10 @@ public ResponseEntity send(XapiRequest request) { * class. */ public ResponseEntity send(GetStateRequest request, Class responseType) { - return _send(request, responseType); + return sendRequest(request, responseType); } - private ResponseEntity _send(XapiRequest request, Class responseType) { + private ResponseEntity sendRequest(XapiRequest request, Class responseType) { final RequestBodySpec r = client From 4fc7771a83ee7f8e7fbc04a2b1b496ae1322f91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20R=C3=A1tkai?= Date: Wed, 18 Jan 2023 16:17:59 +0000 Subject: [PATCH 12/74] fsi --- .../java/dev/learning/xapi/client/XapiClient.java | 13 ++++++------- .../java/dev/learning/xapi/client/XapiRequest.java | 12 ++++++++++++ .../dev/learning/xapi/client/StateRequestIT.java | 10 +++++----- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index dc7d8b6f..c05056c9 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -3,9 +3,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import dev.learning.xapi.model.Actor; +import jakarta.validation.constraints.NotNull; import java.util.HashMap; import lombok.extern.slf4j.Slf4j; -import org.springframework.core.GenericTypeResolver; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; @@ -53,10 +53,8 @@ public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { * @return a {@link ResponseEntity} containing the response object defined by the request * parameter. */ - @SuppressWarnings("unchecked") public ResponseEntity send(XapiRequest request) { - return sendRequest(request, - (Class) GenericTypeResolver.resolveTypeArgument(request.getClass(), XapiRequest.class)); + return sendRequest(request, request.getResponseType()); } /** @@ -87,11 +85,12 @@ public ResponseEntity send(XapiRequest request) { * @throws RuntimeException when the returned state cannot be converted to the expected JAVA * class. */ - public ResponseEntity send(GetStateRequest request, Class responseType) { + public ResponseEntity send(GetStateRequest request, @NotNull Class responseType) { return sendRequest(request, responseType); } - private ResponseEntity sendRequest(XapiRequest request, Class responseType) { + private ResponseEntity sendRequest(XapiRequest request, + @NotNull Class responseType) { final RequestBodySpec r = client @@ -104,7 +103,7 @@ private ResponseEntity sendRequest(XapiRequest request, Class respo return uriBuilder.path(request.getPath()).build(variableMap); }) - .headers(headers -> request.headers(headers)) + .headers(request::headers) ; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java index f8fcd8f3..705a47cd 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java @@ -1,10 +1,13 @@ package dev.learning.xapi.client; +import jakarta.validation.constraints.NotNull; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.experimental.SuperBuilder; +import org.springframework.core.GenericTypeResolver; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.util.Assert; import org.springframework.web.util.UriBuilder; /** @@ -17,6 +20,15 @@ @RequiredArgsConstructor abstract class XapiRequest { + @NotNull + @SuppressWarnings("unchecked") + public Class getResponseType() { + final var responseType = (Class) GenericTypeResolver.resolveTypeArgument(getClass(), + XapiRequest.class); + Assert.notNull(responseType, "XapiRequest resolved generic type must not be null"); + return responseType; + } + /** * Callback method which sets the query parameters for the xAPI request. * diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java index 3461121a..e32d29a1 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java @@ -18,7 +18,7 @@ import org.springframework.http.MediaType; @SpringBootTest(classes = TestApp.class) -public class StateRequestIT { +class StateRequestIT { @Autowired private XapiClient client; @@ -40,7 +40,7 @@ public void init() { } @Test - public void testGivenStateDoesNotExistWhenSendingGetStateRequestThenResponseStatusIsNotFound() { + void testGivenStateDoesNotExistWhenSendingGetStateRequestThenResponseStatusIsNotFound() { // Given State Does Not Exist @@ -56,7 +56,7 @@ public void testGivenStateDoesNotExistWhenSendingGetStateRequestThenResponseStat } @Test - public void testGivenStateExistsWhenSendingGetStateRequestThenResponseBodyIsExpected() { + void testGivenStateExistsWhenSendingGetStateRequestThenResponseBodyIsExpected() { // Given State Exists body = "text body"; @@ -79,7 +79,7 @@ public void testGivenStateExistsWhenSendingGetStateRequestThenResponseBodyIsExpe } @Test - public void testGivenStateExistsWhenSendingTypedGetStateRequestThenResponseBodyIsExpected() { + void testGivenStateExistsWhenSendingTypedGetStateRequestThenResponseBodyIsExpected() { // Given State Exists @@ -100,7 +100,7 @@ public void testGivenStateExistsWhenSendingTypedGetStateRequestThenResponseBodyI } @Test - public void testGivenMultipleStatesExistsWhenSendingGetStatesRequestThenResponseBodyIsExpected() { + void testGivenMultipleStatesExistsWhenSendingGetStatesRequestThenResponseBodyIsExpected() { // Given Multiple States Exists From e79e0858dc301f04ccf88ca96e9ed86aebc6bff9 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 19 Jan 2023 09:50:32 +0000 Subject: [PATCH 13/74] Change author --- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index c05056c9..32c3f965 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -17,7 +17,7 @@ * Client for communicating with LRS or service which implements some of the xAPI communication * resources. * - * @author Thomas Turrell-Croft + * @author István Rátkai (Selindek) * @see xAPI * communication resources From 74afef718dd9f4bdd8d5733aab9f62541815880a Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 19 Jan 2023 10:34:33 +0000 Subject: [PATCH 14/74] Remove unnecessary brackets from superbuilder annotations --- .../main/java/dev/learning/xapi/client/DeleteStateRequest.java | 2 +- .../main/java/dev/learning/xapi/client/DeleteStatesRequest.java | 2 +- .../main/java/dev/learning/xapi/client/PostStateRequest.java | 2 +- .../src/main/java/dev/learning/xapi/client/PutStateRequest.java | 2 +- .../src/main/java/dev/learning/xapi/client/XapiRequest.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index 33d9d8c7..a14f480e 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -15,7 +15,7 @@ * State Document DELETE * @author István Rátkai (Selindek) */ -@SuperBuilder() +@SuperBuilder @Getter @EqualsAndHashCode(callSuper = true) public class DeleteStateRequest extends StateRequest { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index 4d615ec4..e3345ea2 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -12,7 +12,7 @@ * State Document DELETE * @author István Rátkai (Selindek) */ -@SuperBuilder() +@SuperBuilder @EqualsAndHashCode(callSuper = true) public class DeleteStatesRequest extends StatesRequest { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index b63de919..118ce920 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -20,7 +20,7 @@ * Procedure with Requirements * @author István Rátkai (Selindek) */ -@SuperBuilder() +@SuperBuilder @Getter @EqualsAndHashCode(callSuper = true) public class PostStateRequest extends DeleteStateRequest { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index fd6c64ab..5b9dd1b6 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -11,7 +11,7 @@ * State Document PUT * @author István Rátkai (Selindek) */ -@SuperBuilder() +@SuperBuilder public class PutStateRequest extends PostStateRequest { @Override diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java index 705a47cd..932b1578 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java @@ -16,7 +16,7 @@ * @author István Rátkai (Selindek) * @param The type of the response body. Can be {@link Void} for responses without body. */ -@SuperBuilder() +@SuperBuilder @RequiredArgsConstructor abstract class XapiRequest { From e6cf23a08c4ebcab8a7990f41cd49824cff0ca03 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 19 Jan 2023 11:17:59 +0000 Subject: [PATCH 15/74] Configure code coverage --- xapi-client/pom.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/xapi-client/pom.xml b/xapi-client/pom.xml index 14f0534b..440302fd 100644 --- a/xapi-client/pom.xml +++ b/xapi-client/pom.xml @@ -24,7 +24,7 @@ org.projectlombok lombok - true + provided org.springframework.boot @@ -32,4 +32,14 @@ test + + + + + org.jacoco + jacoco-maven-plugin + + + + From 5bccb421afe55f9601302096f7f45a88d8e65b93 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 19 Jan 2023 11:23:23 +0000 Subject: [PATCH 16/74] Use builder for builder name --- xapi-client/lombok.config | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 xapi-client/lombok.config diff --git a/xapi-client/lombok.config b/xapi-client/lombok.config new file mode 100644 index 00000000..b2661bf9 --- /dev/null +++ b/xapi-client/lombok.config @@ -0,0 +1,3 @@ +# Suppress code coverage on Lombok annotations +lombok.addLombokGeneratedAnnotation = true +lombok.builder.className = Builder From 5ee21818f49e84f79d302dc6d4196a3a7a633f8e Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 19 Jan 2023 18:21:14 +0000 Subject: [PATCH 17/74] Add agent consumer builder to StatesRequest --- .../learning/xapi/client/StatesRequest.java | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 7127bb2a..ffa7046a 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -1,10 +1,14 @@ package dev.learning.xapi.client; +import dev.learning.xapi.model.Account; import dev.learning.xapi.model.Actor; +import dev.learning.xapi.model.Actor.Builder; +import dev.learning.xapi.model.Agent; import java.net.URI; import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.function.Consumer; import lombok.Builder.Default; import lombok.Getter; import lombok.NonNull; @@ -34,8 +38,9 @@ abstract class StatesRequest extends XapiRequest { * The agent query parameter. */ @NonNull - private final Actor agent; + private final Agent agent; + // TODO should not have a default /** * The optional registration query parameter. */ @@ -60,4 +65,46 @@ protected void query(UriBuilder uriBuilder, Map variableMap) { variableMap.put("activityId", activityId); variableMap.put("agent", agent); } + + public static abstract class Builder, B extends StatesRequest.Builder> extends XapiRequest.Builder { + + /** + * Consumer Builder for agent. + * + * @param account The Consumer Builder for agent. + * + * @return This builder + * + * @see StatesRequest#agent + */ + public B agent(Consumer> account) { + + final Agent.Builder builder = Agent.builder(); + + account.accept(builder); + + return agent(builder.build()); + + } + + /** + * Sets the agent. + * + * @param account The Agent of the StatesRequest. + * + * @return This builder + * + * @see StatesRequest#agent + */ + public B agent(Agent agent) { + + this.agent = agent; + + return self(); + + } + + } + + } From 26982ca2954e30c3b6447b1c1467f4e4ff339cd4 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 19 Jan 2023 18:22:39 +0000 Subject: [PATCH 18/74] Should use NonNull instead of NotNull --- .../src/main/java/dev/learning/xapi/client/XapiRequest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java index 932b1578..11a76112 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java @@ -1,7 +1,8 @@ package dev.learning.xapi.client; -import jakarta.validation.constraints.NotNull; import java.util.Map; + +import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.experimental.SuperBuilder; import org.springframework.core.GenericTypeResolver; @@ -20,7 +21,7 @@ @RequiredArgsConstructor abstract class XapiRequest { - @NotNull + @NonNull @SuppressWarnings("unchecked") public Class getResponseType() { final var responseType = (Class) GenericTypeResolver.resolveTypeArgument(getClass(), From ab3a2ff151d22fcec645dee8994265eacf2e8322 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 20 Jan 2023 11:29:01 +0000 Subject: [PATCH 19/74] Add builder method for activityId which accepts a String --- .../learning/xapi/client/StatesRequest.java | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index ffa7046a..3f98cf97 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -1,8 +1,5 @@ package dev.learning.xapi.client; -import dev.learning.xapi.model.Account; -import dev.learning.xapi.model.Actor; -import dev.learning.xapi.model.Actor.Builder; import dev.learning.xapi.model.Agent; import java.net.URI; import java.util.Map; @@ -103,7 +100,41 @@ public B agent(Agent agent) { return self(); } - + + /** + * Sets the activityId. + * + * @param activityId The activityId of the StatesRequest. + * + * @return This builder + * + * @see StatesRequest#activityId + */ + public B activityId(String activityId) { + + this.activityId = URI.create(activityId); + + return self(); + + } + + /** + * Sets the activityId. + * + * @param activityId The activityId of the StatesRequest. + * + * @return This builder + * + * @see StatesRequest#activityId + */ + public B activityId(URI activityId) { + + this.activityId = activityId; + + return self(); + + } + } From d4c164cff52b74558d13dadc4b3254a41ab2afc9 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 20 Jan 2023 12:23:22 +0000 Subject: [PATCH 20/74] Work in progress but works with request builder --- .../dev/learning/xapi/client/XapiClient.java | 57 ++++++++++-- .../learning/xapi/client/StateRequestIT.java | 88 ++++++++++++++++++- 2 files changed, 137 insertions(+), 8 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 32c3f965..d8635409 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -2,9 +2,13 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; + +import dev.learning.xapi.client.PutStateRequest.Builder; import dev.learning.xapi.model.Actor; -import jakarta.validation.constraints.NotNull; import java.util.HashMap; +import java.util.function.Consumer; + +import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; @@ -56,7 +60,46 @@ public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { public ResponseEntity send(XapiRequest request) { return sendRequest(request, request.getResponseType()); } + + + // public static abstract class Builder, B extends StatesRequest.Builder> extends XapiRequest.Builder { + + + + public > ResponseEntity putState(PutStateRequest.Builder putStateRequest) { + + var request = putStateRequest.build(); + + return sendRequest(request, request.getResponseType()); + + } + + + + public > ResponseEntity putState(Consumer> putStateRequest) { + + final PutStateRequest.Builder builder = PutStateRequest.builder(); + + putStateRequest.accept(builder); + + return putState(builder); + + } + + +/* + public Builder account(Consumer account) { + + final Account.Builder builder = Account.builder(); + + account.accept(builder); + return account(builder.build()); + } +*/ + + + /** *

* Convenient type-safe method for sending a {@link GetStateRequest} which expects an instance of @@ -85,27 +128,25 @@ public ResponseEntity send(XapiRequest request) { * @throws RuntimeException when the returned state cannot be converted to the expected JAVA * class. */ - public ResponseEntity send(GetStateRequest request, @NotNull Class responseType) { + public ResponseEntity send(GetStateRequest request, @NonNull Class responseType) { return sendRequest(request, responseType); } private ResponseEntity sendRequest(XapiRequest request, - @NotNull Class responseType) { + @NonNull Class responseType) { final RequestBodySpec r = client .method(request.getMethod()) .uri(uriBuilder -> { - final var variableMap = new HashMap(); + final var variableMap = new HashMap(); request.query(uriBuilder, variableMap); convertActors(variableMap); return uriBuilder.path(request.getPath()).build(variableMap); }) - .headers(request::headers) - - ; + .headers(request::headers); final var body = request.getBody(); @@ -137,4 +178,6 @@ private void convertActors(HashMap variableMap) { }); } + + } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java index e32d29a1..905e64de 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java @@ -7,9 +7,18 @@ import dev.learning.xapi.model.Actor; import dev.learning.xapi.model.Agent; +import software.amazon.awssdk.services.ses.SesClient; +import software.amazon.awssdk.services.ses.model.Body; +import software.amazon.awssdk.services.ses.model.Content; +import software.amazon.awssdk.services.ses.model.Destination; +import software.amazon.awssdk.services.ses.model.Message; +import software.amazon.awssdk.services.ses.model.SendEmailRequest; + import java.awt.Point; import java.net.URI; import java.util.UUID; + +import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -24,7 +33,7 @@ class StateRequestIT { private XapiClient client; private URI activityId; - private Actor agent; + private Agent agent; private String stateId; private Object body; private MediaType contentType; @@ -126,5 +135,82 @@ void testGivenMultipleStatesExistsWhenSendingGetStatesRequestThenResponseBodyIsE assertThat(response.getBody(), allOf(hasItem(stateId1), hasItem(stateId2))); } + + + + + + @Test + void test1() { + // Given Multiple States Exists + + Agent agent = Agent.builder().name("admin").mbox("mailto:admin@learning.dev").build(); + + /* + + client.putStateRequest(PutStateRequest.builder() + + .activityId(URI.create("https://example.com/")) + + .agent(agent) + + .stateId("resume") + + .body(body)); + */ + + } + + + @Test + void test2() { + + // Given Multiple States Exists + + client.putState(PutStateRequest.builder() + + .activityId(URI.create("https://example.com/")) + + .agent(agent) + + .stateId("resume") + + .body(body) + + .contentType(MediaType.APPLICATION_JSON)); + + } + + @Test + void test3() { + + client.putState(r -> r + + .activityId("https://example.com/") + + .agent(a -> a.mbox("hello").name("world")) + + .stateId("resume") + + .body(body) + + .contentType(MediaType.APPLICATION_JSON)); + + } + + public void test4() { + + PutStateRequest.builder() + + .activityId("https://example.com/") + + .agent(a -> a.mbox("hello").name("world")) + + .stateId("resume") + + .body(body); + + } + } From 06b87fe87f1f26a2c1f1eda8fdb53ed1780f2e8c Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 20 Jan 2023 17:32:58 +0000 Subject: [PATCH 21/74] wip --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 70311f20..dc02ecd4 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,20 @@ xAPI Java helps you to create applications that send or receive xAPI [Statements](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#statements) or [Documents](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#10-documents). +## xAPI Java Client + +```java +client.putStateRequest(r -> r.activityId(activityId) + + .agent(agent) + + .stateId("resume") + + .body(body) + + .contentType(contentType)); +``` + ## xAPI Java Model The xAPI Model has a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface). Objects are [immutable](https://en.wikipedia.org/wiki/Immutable_object). @@ -43,6 +57,21 @@ final Statement statement = Statement.builder() .build(); ``` +```java +Agent agent = new Agent(); +agent.setMbox("mailto:info@tincanapi.com"); + +Verb verb = new Verb("http://adlnet.gov/expapi/verbs/attempted"); + +Activity activity = new Activity("http://rusticisoftware.github.com/TinCanJava"); + +Statement st = new Statement(); +st.setActor(agent); +st.setVerb(verb); +st.setObject(activity); + +``` + ### Deserializing Statements The Jackson ObjectMapper can be used to deserialize statements into Java objects. From b43e3f4f9ee97bea9c2f2bf61c20bee27e83cd20 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 14:18:15 +0000 Subject: [PATCH 22/74] tip --- .../xapi/client/DeleteStateRequest.java | 22 -- .../xapi/client/PostStateRequest.java | 24 ++- .../learning/xapi/client/StatesRequest.java | 193 +++++++++++------- .../dev/learning/xapi/client/XapiClient.java | 56 ++--- .../dev/learning/xapi/client/XapiRequest.java | 22 +- 5 files changed, 164 insertions(+), 153 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index a14f480e..a107338e 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -1,10 +1,8 @@ package dev.learning.xapi.client; -import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.experimental.SuperBuilder; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; /** @@ -20,26 +18,6 @@ @EqualsAndHashCode(callSuper = true) public class DeleteStateRequest extends StateRequest { - /** - * The If-Match header of the request. - */ - private final String match; - - /** - * The If-None-Match headers of the request. - */ - private final List noneMatch; - - @Override - protected void headers(HttpHeaders headers) { - if (match != null) { - headers.set(HttpHeaders.IF_MATCH, match); - } - if (noneMatch != null && !noneMatch.isEmpty()) { - headers.addAll(HttpHeaders.IF_NONE_MATCH, noneMatch); - } - } - @Override protected HttpMethod getMethod() { return HttpMethod.DELETE; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index 118ce920..228334d5 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -1,6 +1,5 @@ package dev.learning.xapi.client; -import lombok.Builder.Default; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; @@ -23,26 +22,31 @@ @SuperBuilder @Getter @EqualsAndHashCode(callSuper = true) -public class PostStateRequest extends DeleteStateRequest { +public class PostStateRequest extends StateRequest { /** * The Content-Type header of the request. Default is * application/json. */ @NonNull - @Default - private MediaType contentType = MediaType.APPLICATION_JSON; + private MediaType contentType; /** - * The body of the request. + * The state object to store. */ @NonNull - private final Object body; + private final Object state; @Override protected void headers(HttpHeaders headers) { super.headers(headers); - headers.setContentType(contentType); + + if (contentType != null) { + headers.setContentType(contentType); + } else if (headers.getContentType() == null) { + headers.setContentType(MediaType.APPLICATION_JSON); + } + } @Override @@ -50,4 +54,10 @@ protected HttpMethod getMethod() { return HttpMethod.POST; } + @Override + protected Object getBody() { + + return state; + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 3f98cf97..aaba52ad 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -6,7 +6,6 @@ import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; -import lombok.Builder.Default; import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; @@ -37,12 +36,11 @@ abstract class StatesRequest extends XapiRequest { @NonNull private final Agent agent; - // TODO should not have a default + // TODO why not final? Because it is Optional? /** * The optional registration query parameter. */ - @Default - private Optional registration = Optional.empty(); + private UUID registration; @Override protected String getPath() { @@ -57,85 +55,124 @@ protected void query(UriBuilder uriBuilder, Map variableMap) { .queryParam("agent", "{agent}") - .queryParamIfPresent("registration", registration); + .queryParamIfPresent("registration", Optional.ofNullable(registration)); variableMap.put("activityId", activityId); variableMap.put("agent", agent); } - - public static abstract class Builder, B extends StatesRequest.Builder> extends XapiRequest.Builder { - - /** - * Consumer Builder for agent. - * - * @param account The Consumer Builder for agent. - * - * @return This builder - * - * @see StatesRequest#agent - */ - public B agent(Consumer> account) { - - final Agent.Builder builder = Agent.builder(); - - account.accept(builder); - - return agent(builder.build()); - - } - - /** - * Sets the agent. - * - * @param account The Agent of the StatesRequest. - * - * @return This builder - * - * @see StatesRequest#agent - */ - public B agent(Agent agent) { - - this.agent = agent; - - return self(); - - } - - /** - * Sets the activityId. - * - * @param activityId The activityId of the StatesRequest. - * - * @return This builder - * - * @see StatesRequest#activityId - */ - public B activityId(String activityId) { - - this.activityId = URI.create(activityId); - - return self(); - - } - - /** - * Sets the activityId. - * - * @param activityId The activityId of the StatesRequest. - * - * @return This builder - * - * @see StatesRequest#activityId - */ - public B activityId(URI activityId) { - - this.activityId = activityId; - - return self(); - - } + + public static abstract class Builder, B extends StatesRequest.Builder> + extends XapiRequest.Builder { + + /** + * Consumer Builder for agent. + * + * @param account The Consumer Builder for agent. + * + * @return This builder + * + * @see StatesRequest#agent + */ + public B agent(Consumer> account) { + + final Agent.Builder builder = Agent.builder(); + + account.accept(builder); + + return agent(builder.build()); + + } + + /** + * Sets the agent. + * + * @param account The Agent of the StatesRequest. + * + * @return This builder + * + * @see StatesRequest#agent + */ + public B agent(Agent agent) { + + this.agent = agent; + + return self(); + + } + + /** + * Sets the activityId. + * + * @param activityId The activityId of the StatesRequest. + * + * @return This builder + * + * @see StatesRequest#activityId + */ + public B activityId(String activityId) { + + this.activityId = URI.create(activityId); + + return self(); + + } + + /** + * Sets the activityId. + * + * @param activityId The activityId of the StatesRequest. + * + * @return This builder + * + * @see StatesRequest#activityId + */ + public B activityId(URI activityId) { + + this.activityId = activityId; + + return self(); + + } + + + + /** + * Sets the registration. + * + * @param registration The registration of the StatesRequest. + * + * @return This builder + * + * @see StatesRequest#registration + */ + public B registration(String registration) { + + this.registration = UUID.fromString(registration); + + return self(); + + } + + /** + * Sets the registration. + * + * @param registration The registration of the StatesRequest. + * + * @return This builder + * + * @see StatesRequest#registration + */ + public B registration(UUID registration) { + + this.registration = registration; + + return self(); + + } + + } - + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index d8635409..21e1abc4 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -2,12 +2,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; - -import dev.learning.xapi.client.PutStateRequest.Builder; import dev.learning.xapi.model.Actor; import java.util.HashMap; import java.util.function.Consumer; - import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatusCode; @@ -35,10 +32,10 @@ public class XapiClient { /** * Default constructor for XapiClient. * - * @param builder a {@link WebClient.Builder} object. The caller must set the baseUrl and the - * authorization header. + * @param builder a {@link WebClient.Builder} object. The caller must set the baseUrl and the + * authorization header. * @param objectMapper an {@link ObjectMapper}. It is used for converting {@link Actor} query - * parameters to JSON string during xAPI requests. + * parameters to JSON string during xAPI requests. */ public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { this.objectMapper = objectMapper; @@ -52,7 +49,7 @@ public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { /** * Sends an xAPI request. * - * @param The response type is defined by the request parameter. + * @param The response type is defined by the request parameter. * @param request an {@link XapiRequest} object describing the xAPI request. * @return a {@link ResponseEntity} containing the response object defined by the request * parameter. @@ -60,46 +57,29 @@ public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { public ResponseEntity send(XapiRequest request) { return sendRequest(request, request.getResponseType()); } - - - // public static abstract class Builder, B extends StatesRequest.Builder> extends XapiRequest.Builder { - - public > ResponseEntity putState(PutStateRequest.Builder putStateRequest) { + public , B extends XapiRequest.Builder> ResponseEntity send( + XapiRequest.Builder xapiRequest) { - var request = putStateRequest.build(); + var request = xapiRequest.build(); - return sendRequest(request, request.getResponseType()); - - } + return sendRequest(request, request.getResponseType()); + } - - public > ResponseEntity putState(Consumer> putStateRequest) { - - final PutStateRequest.Builder builder = PutStateRequest.builder(); + public > ResponseEntity putState( + Consumer> putStateRequest) { - putStateRequest.accept(builder); - - return putState(builder); + final PutStateRequest.Builder builder = PutStateRequest.builder(); - } + putStateRequest.accept(builder); - -/* - public Builder account(Consumer account) { + return send(builder); - final Account.Builder builder = Account.builder(); + } - account.accept(builder); - return account(builder.build()); - } -*/ - - - /** *

* Convenient type-safe method for sending a {@link GetStateRequest} which expects an instance of @@ -118,15 +98,15 @@ public Builder account(Consumer account) { * request then the state is returned as a String. *

* - * @param The response type is defined by the responseType parameter. - * @param request an {@link GetStateRequest} object. + * @param The response type is defined by the responseType parameter. + * @param request an {@link GetStateRequest} object. * @param responseType a {@link Class} object defining the response type of the returning state. * @return a {@link ResponseEntity} containing the response object . * @see State * Resources Description * @throws RuntimeException when the returned state cannot be converted to the expected JAVA - * class. + * class. */ public ResponseEntity send(GetStateRequest request, @NonNull Class responseType) { return sendRequest(request, responseType); diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java index 11a76112..2b1eecd7 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java @@ -1,7 +1,8 @@ package dev.learning.xapi.client; import java.util.Map; - +import lombok.Builder.Default; +import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.experimental.SuperBuilder; @@ -18,14 +19,19 @@ * @param The type of the response body. Can be {@link Void} for responses without body. */ @SuperBuilder +@Getter @RequiredArgsConstructor abstract class XapiRequest { + @NonNull + @Default + private final HttpHeaders httpHeaders = new HttpHeaders(); + @NonNull @SuppressWarnings("unchecked") public Class getResponseType() { - final var responseType = (Class) GenericTypeResolver.resolveTypeArgument(getClass(), - XapiRequest.class); + final var responseType = + (Class) GenericTypeResolver.resolveTypeArgument(getClass(), XapiRequest.class); Assert.notNull(responseType, "XapiRequest resolved generic type must not be null"); return responseType; } @@ -33,19 +39,19 @@ public Class getResponseType() { /** * Callback method which sets the query parameters for the xAPI request. * - * @param uribuilder an {@link UriBuilder} object. The methods add query templates to the - * builder. + * @param uribuilder an {@link UriBuilder} object. The methods add query templates to the builder. * @param variableMap a {@link Map} containing the actual values for the query templates. */ - protected void query(UriBuilder uribuilder, Map variableMap) { - } + protected void query(UriBuilder uribuilder, Map variableMap) {} /** * Callback method which sets the headers for the xAPI request. * * @param headers a {@link HttpHeaders} object. */ - protected void headers(HttpHeaders headers) { + protected void headers(HttpHeaders httpHeaders) { + httpHeaders.addAll(this.httpHeaders); + } /** From a299faca159d8859747fb37e0b38b6597316fb48 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 16:16:26 +0000 Subject: [PATCH 23/74] stuff not compling for a while --- xapi-client/pom.xml | 5 + .../xapi/client/DeleteStateRequest.java | 4 - .../xapi/client/DeleteStatesRequest.java | 2 - .../xapi/client/PostStateRequest.java | 23 +- .../client/{XapiRequest.java => Request.java} | 23 +- .../learning/xapi/client/StatesRequest.java | 4 +- .../dev/learning/xapi/client/XapiClient.java | 15 +- .../xapi/client/PutStateRequestTests.java | 107 +++++++ .../learning/xapi/client/StateRequestIT.java | 300 ++++++++---------- 9 files changed, 285 insertions(+), 198 deletions(-) rename xapi-client/src/main/java/dev/learning/xapi/client/{XapiRequest.java => Request.java} (87%) create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java diff --git a/xapi-client/pom.xml b/xapi-client/pom.xml index 440302fd..a3671ed9 100644 --- a/xapi-client/pom.xml +++ b/xapi-client/pom.xml @@ -31,6 +31,11 @@ spring-boot-starter-test test + + org.apache.commons + commons-lang3 + text + diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index a107338e..73d77289 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -1,7 +1,5 @@ package dev.learning.xapi.client; -import lombok.EqualsAndHashCode; -import lombok.Getter; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; @@ -14,8 +12,6 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -@Getter -@EqualsAndHashCode(callSuper = true) public class DeleteStateRequest extends StateRequest { @Override diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index e3345ea2..a2b3652c 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -1,6 +1,5 @@ package dev.learning.xapi.client; -import lombok.EqualsAndHashCode; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; @@ -13,7 +12,6 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -@EqualsAndHashCode(callSuper = true) public class DeleteStatesRequest extends StatesRequest { @Override diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index 228334d5..18869faa 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -4,7 +4,6 @@ import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -29,7 +28,7 @@ public class PostStateRequest extends StateRequest { * application/json. */ @NonNull - private MediaType contentType; + private final MediaType contentType; /** * The state object to store. @@ -37,17 +36,15 @@ public class PostStateRequest extends StateRequest { @NonNull private final Object state; - @Override - protected void headers(HttpHeaders headers) { - super.headers(headers); - - if (contentType != null) { - headers.setContentType(contentType); - } else if (headers.getContentType() == null) { - headers.setContentType(MediaType.APPLICATION_JSON); - } - } + /* + * @Override protected void headers(HttpHeaders headers) { super.headers(headers); + * + * if (contentType != null) { headers.setContentType(contentType); } else if + * (headers.getContentType() == null) { headers.setContentType(MediaType.APPLICATION_JSON); } + * + * } + */ @Override protected HttpMethod getMethod() { @@ -60,4 +57,6 @@ protected Object getBody() { return state; } + + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java similarity index 87% rename from xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java rename to xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 2b1eecd7..7bfa3e71 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -21,7 +21,7 @@ @SuperBuilder @Getter @RequiredArgsConstructor -abstract class XapiRequest { +abstract class Request { @NonNull @Default @@ -31,7 +31,7 @@ abstract class XapiRequest { @SuppressWarnings("unchecked") public Class getResponseType() { final var responseType = - (Class) GenericTypeResolver.resolveTypeArgument(getClass(), XapiRequest.class); + (Class) GenericTypeResolver.resolveTypeArgument(getClass(), Request.class); Assert.notNull(responseType, "XapiRequest resolved generic type must not be null"); return responseType; } @@ -44,15 +44,19 @@ public Class getResponseType() { */ protected void query(UriBuilder uribuilder, Map variableMap) {} + + /** * Callback method which sets the headers for the xAPI request. * * @param headers a {@link HttpHeaders} object. */ - protected void headers(HttpHeaders httpHeaders) { - httpHeaders.addAll(this.httpHeaders); - - } + /* + * + * protected void headers(HttpHeaders httpHeaders) { httpHeaders.addAll(this.httpHeaders); + * + * } + */ /** * The request method. @@ -77,4 +81,11 @@ protected Object getBody() { return null; } + + + public static abstract class Builder, B extends Request.Builder> { + + } + + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index aaba52ad..59e84382 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -22,7 +22,7 @@ */ @SuperBuilder @Getter -abstract class StatesRequest extends XapiRequest { +abstract class StatesRequest extends Request { /** * The activityId query parameter. @@ -62,7 +62,7 @@ protected void query(UriBuilder uriBuilder, Map variableMap) { } public static abstract class Builder, B extends StatesRequest.Builder> - extends XapiRequest.Builder { + extends Request.Builder { /** * Consumer Builder for agent. diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 21e1abc4..7a4e4afe 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -50,17 +50,17 @@ public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { * Sends an xAPI request. * * @param The response type is defined by the request parameter. - * @param request an {@link XapiRequest} object describing the xAPI request. + * @param request an {@link Request} object describing the xAPI request. * @return a {@link ResponseEntity} containing the response object defined by the request * parameter. */ - public ResponseEntity send(XapiRequest request) { + public ResponseEntity send(Request request) { return sendRequest(request, request.getResponseType()); } - public , B extends XapiRequest.Builder> ResponseEntity send( - XapiRequest.Builder xapiRequest) { + public , B extends Request.Builder> ResponseEntity send( + Request.Builder xapiRequest) { var request = xapiRequest.build(); @@ -94,7 +94,7 @@ public > Resp * then a {@link RuntimeException} is thrown. *

*

- * If the generic {@link XapiClient#send(XapiRequest)} method is used with {@link GetStateRequest} + * If the generic {@link XapiClient#send(Request)} method is used with {@link GetStateRequest} * request then the state is returned as a String. *

* @@ -112,7 +112,7 @@ public ResponseEntity send(GetStateRequest request, @NonNull Class res return sendRequest(request, responseType); } - private ResponseEntity sendRequest(XapiRequest request, + private ResponseEntity sendRequest(Request request, @NonNull Class responseType) { final RequestBodySpec r = client @@ -126,7 +126,8 @@ private ResponseEntity sendRequest(XapiRequest request, return uriBuilder.path(request.getPath()).build(variableMap); }) - .headers(request::headers); + //.headers(h -> request.getHttpHeaders()) + ; final var body = request.getBody(); diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java new file mode 100644 index 00000000..463f383a --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java @@ -0,0 +1,107 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; + +/** + * PutStateRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("PutStateRequest Tests") +class PutStateRequestTests { + + + // activityId | Required + // agent | Required + // registration | Optional + // stateId | Required + + + @Test + void WhenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building PutStateRequest With All Parameters + assertDoesNotThrow(() -> { + var x = PutStateRequest.builder() + + // Parameters + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + // Body + + .state("Hello World!") + + // Headers + + .contentType(MediaType.TEXT_PLAIN) + + .httpHeaders(null) + + .build(); + + }); + + + + // Then No Exception Is Thrown + + } + + + @Test + void whenDeserializingAboutThenResultIsInstanceOfAbout() { + + // When Building PutStateRequest With All Parameters + assertDoesNotThrow(() -> { + PutStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark").build(); + }); + + // Then No Exception Is Thrown + + } + + + + @Test + void when() { + + // When Building PutStateRequest With All Parameters + PutStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark").build(); + + // Then No Exception Is Thrown + + } + + + +} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java index 905e64de..7f2cddd8 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java @@ -1,24 +1,11 @@ package dev.learning.xapi.client; -import static org.hamcrest.CoreMatchers.allOf; -import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; - -import dev.learning.xapi.model.Actor; import dev.learning.xapi.model.Agent; -import software.amazon.awssdk.services.ses.SesClient; -import software.amazon.awssdk.services.ses.model.Body; -import software.amazon.awssdk.services.ses.model.Content; -import software.amazon.awssdk.services.ses.model.Destination; -import software.amazon.awssdk.services.ses.model.Message; -import software.amazon.awssdk.services.ses.model.SendEmailRequest; - import java.awt.Point; import java.net.URI; import java.util.UUID; - -import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -35,7 +22,7 @@ class StateRequestIT { private URI activityId; private Agent agent; private String stateId; - private Object body; + private Object state; private MediaType contentType; @BeforeEach @@ -44,7 +31,7 @@ public void init() { activityId = URI.create("http://learning.dev/" + UUID.randomUUID()); agent = Agent.builder().name("admin").mbox("mailto:admin@learning.dev").build(); stateId = UUID.randomUUID().toString(); - body = new Point(1, 2); + state = new Point(1, 2); contentType = MediaType.APPLICATION_JSON; } @@ -55,8 +42,8 @@ void testGivenStateDoesNotExistWhenSendingGetStateRequestThenResponseStatusIsNot // When Sending GetStateRequest - final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) - .stateId(stateId).build(); + final var getRequest = + GetStateRequest.builder().activityId(activityId).agent(agent).stateId(stateId).build(); final var response = client.send(getRequest); // Then Response Status Is Not Found @@ -64,153 +51,136 @@ void testGivenStateDoesNotExistWhenSendingGetStateRequestThenResponseStatusIsNot assertThat(response.getStatusCode(), is(HttpStatus.NOT_FOUND)); } - @Test - void testGivenStateExistsWhenSendingGetStateRequestThenResponseBodyIsExpected() { - - // Given State Exists - body = "text body"; - contentType = MediaType.TEXT_PLAIN; - - final var putRequest = PutStateRequest.builder().activityId(activityId).agent(agent) - .stateId(stateId).body(body).contentType(contentType).build(); - final var putResponse = client.send(putRequest); - assertThat(putResponse.getStatusCode().value(), is(204)); + /* + * + * @Test void testGivenStateExistsWhenSendingGetStateRequestThenResponseBodyIsExpected() { + * + * // Given State Exists state = "text body"; contentType = MediaType.TEXT_PLAIN; + * + * final var putRequest = PutStateRequestTests.builder().activityId(activityId).agent(agent) + * .stateId(stateId).state(state).contentType(contentType).build(); final var putResponse = + * client.send(putRequest); assertThat(putResponse.getStatusCode().value(), is(204)); + * + * // When Sending GetStateRequest + * + * final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) + * .stateId(stateId).build(); final var response = client.send(getRequest); + * + * // Then Response Body Is Expected + * + * assertThat(response.getBody(), is(state)); } + * + * @Test void testGivenStateExistsWhenSendingTypedGetStateRequestThenResponseBodyIsExpected() { + * + * // Given State Exists + * + * final var putRequest = PutStateRequestTests.builder().activityId(activityId).agent(agent) + * .stateId(stateId).state(state).contentType(contentType).build(); final var putResponse = + * client.send(putRequest); assertThat(putResponse.getStatusCode().value(), is(204)); + * + * // When Sending Typed GetStateRequest + * + * final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) + * .stateId(stateId).build(); final var response = client.send(getRequest, Point.class); + * + * // Then Response Body Is Expected + * + * assertThat(response.getBody(), is(state)); } + * + * @Test void testGivenMultipleStatesExistsWhenSendingGetStatesRequestThenResponseBodyIsExpected() + * { + * + * // Given Multiple States Exists + * + * final var stateId1 = UUID.randomUUID().toString(); final var stateId2 = + * UUID.randomUUID().toString(); + * + * final var putRequest1 = PutStateRequestTests.builder().activityId(activityId).agent(agent) + * .stateId(stateId1).state(state).contentType(contentType).build(); final var putResponse1 = + * client.send(putRequest1); assertThat(putResponse1.getStatusCode().value(), is(204)); + * + * final var putRequest2 = PutStateRequestTests.builder().activityId(activityId).agent(agent) + * .stateId(stateId2).state(state).contentType(contentType).build(); final var putResponse2 = + * client.send(putRequest2); assertThat(putResponse2.getStatusCode().value(), is(204)); + * + * // When Sending GetStatesRequest + * + * final var getRequest = GetStatesRequest.builder().activityId(activityId).agent(agent).build(); + * final var response = client.send(getRequest); + * + * // Then Response Body Is Expected + * + * assertThat(response.getBody(), allOf(hasItem(stateId1), hasItem(stateId2))); } + * + * + * + * + * + * @Test void test1() { + * + * // Given Multiple States Exists + * + * Agent agent = Agent.builder().name("admin").mbox("mailto:admin@learning.dev").build(); + * + * + * client.putStateRequest(PutStateRequest.builder() + * + * .activityId(URI.create("https://example.com/")) + * + * .agent(agent) + * + * .stateId("resume") + * + * .state(body)); + * + * } + * + * + * @Test void test2() { + * + * client.send(PutStateRequestTests.builder() + * + * .activityId(URI.create("https://example.com/")) + * + * .agent(agent) + * + * .stateId("resume") + * + * .state(state) + * + * .contentType(MediaType.APPLICATION_JSON)); + * + * } + * + * @Test void test3() { + * + * client.putState(r -> r + * + * .activityId("https://example.com/") + * + * .agent(a -> a.mbox("hello").name("world")) + * + * .stateId("resume") + * + * .state(state) + * + * .contentType(MediaType.APPLICATION_JSON)); + * + * } + * + * public void test4() { + * + * PutStateRequestTests.builder() + * + * .activityId("https://example.com/") + * + * .agent(a -> a.mbox("hello").name("world")) + * + * .stateId("resume") + * + * .state(state); + * + * } + */ - // When Sending GetStateRequest - - final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) - .stateId(stateId).build(); - final var response = client.send(getRequest); - - // Then Response Body Is Expected - - assertThat(response.getBody(), is(body)); - } - - @Test - void testGivenStateExistsWhenSendingTypedGetStateRequestThenResponseBodyIsExpected() { - - // Given State Exists - - final var putRequest = PutStateRequest.builder().activityId(activityId).agent(agent) - .stateId(stateId).body(body).contentType(contentType).build(); - final var putResponse = client.send(putRequest); - assertThat(putResponse.getStatusCode().value(), is(204)); - - // When Sending Typed GetStateRequest - - final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) - .stateId(stateId).build(); - final var response = client.send(getRequest, Point.class); - - // Then Response Body Is Expected - - assertThat(response.getBody(), is(body)); - } - - @Test - void testGivenMultipleStatesExistsWhenSendingGetStatesRequestThenResponseBodyIsExpected() { - - // Given Multiple States Exists - - final var stateId1 = UUID.randomUUID().toString(); - final var stateId2 = UUID.randomUUID().toString(); - - final var putRequest1 = PutStateRequest.builder().activityId(activityId).agent(agent) - .stateId(stateId1).body(body).contentType(contentType).build(); - final var putResponse1 = client.send(putRequest1); - assertThat(putResponse1.getStatusCode().value(), is(204)); - - final var putRequest2 = PutStateRequest.builder().activityId(activityId).agent(agent) - .stateId(stateId2).body(body).contentType(contentType).build(); - final var putResponse2 = client.send(putRequest2); - assertThat(putResponse2.getStatusCode().value(), is(204)); - - // When Sending GetStatesRequest - - final var getRequest = GetStatesRequest.builder().activityId(activityId).agent(agent).build(); - final var response = client.send(getRequest); - - // Then Response Body Is Expected - - assertThat(response.getBody(), allOf(hasItem(stateId1), hasItem(stateId2))); - } - - - - - - @Test - void test1() { - - // Given Multiple States Exists - - Agent agent = Agent.builder().name("admin").mbox("mailto:admin@learning.dev").build(); - - /* - - client.putStateRequest(PutStateRequest.builder() - - .activityId(URI.create("https://example.com/")) - - .agent(agent) - - .stateId("resume") - - .body(body)); - */ - - } - - - @Test - void test2() { - - // Given Multiple States Exists - - client.putState(PutStateRequest.builder() - - .activityId(URI.create("https://example.com/")) - - .agent(agent) - - .stateId("resume") - - .body(body) - - .contentType(MediaType.APPLICATION_JSON)); - - } - - @Test - void test3() { - - client.putState(r -> r - - .activityId("https://example.com/") - - .agent(a -> a.mbox("hello").name("world")) - - .stateId("resume") - - .body(body) - - .contentType(MediaType.APPLICATION_JSON)); - - } - - public void test4() { - - PutStateRequest.builder() - - .activityId("https://example.com/") - - .agent(a -> a.mbox("hello").name("world")) - - .stateId("resume") - - .body(body); - - } - } From d1a2791e716a590b0a2313ed4043b074c19af48d Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 17:01:26 +0000 Subject: [PATCH 24/74] this compiles --- .../xapi/client/PostStateRequest.java | 20 -- .../learning/xapi/client/PutStateRequest.java | 2 + .../learning/xapi/client/StateRequest.java | 9 +- .../dev/learning/xapi/client/XapiClient.java | 164 --------------- .../xapi/client/PutStateRequestTests.java | 107 ---------- .../learning/xapi/client/StateRequestIT.java | 186 ------------------ .../dev/learning/xapi/client/TestApp.java | 33 ---- 7 files changed, 3 insertions(+), 518 deletions(-) delete mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java delete mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java delete mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java delete mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index 18869faa..ded21e2f 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -1,11 +1,9 @@ package dev.learning.xapi.client; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; /** * Request for posting a single State document. @@ -20,32 +18,14 @@ */ @SuperBuilder @Getter -@EqualsAndHashCode(callSuper = true) public class PostStateRequest extends StateRequest { - /** - * The Content-Type header of the request. Default is - * application/json. - */ - @NonNull - private final MediaType contentType; - /** * The state object to store. */ @NonNull private final Object state; - - /* - * @Override protected void headers(HttpHeaders headers) { super.headers(headers); - * - * if (contentType != null) { headers.setContentType(contentType); } else if - * (headers.getContentType() == null) { headers.setContentType(MediaType.APPLICATION_JSON); } - * - * } - */ - @Override protected HttpMethod getMethod() { return HttpMethod.POST; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index 5b9dd1b6..56d81db3 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -14,6 +14,8 @@ @SuperBuilder public class PutStateRequest extends PostStateRequest { + + // @Override @Override protected HttpMethod getMethod() { return HttpMethod.PUT; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index 647ffc74..e2f0ff4c 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -1,10 +1,8 @@ package dev.learning.xapi.client; -import java.util.Map; import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; -import org.springframework.web.util.UriBuilder; /** * Abstract superclass for state requests manipulating a single state document. @@ -22,10 +20,5 @@ abstract class StateRequest extends StatesRequest { @NonNull private final String stateId; - @Override - protected void query(UriBuilder uriBuilder, Map variableMap) { - super.query(uriBuilder, variableMap); - uriBuilder.queryParam("stateId", "{stateId}"); - variableMap.put("stateId", stateId); - } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java deleted file mode 100644 index 7a4e4afe..00000000 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ /dev/null @@ -1,164 +0,0 @@ -package dev.learning.xapi.client; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import dev.learning.xapi.model.Actor; -import java.util.HashMap; -import java.util.function.Consumer; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatusCode; -import org.springframework.http.ResponseEntity; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; -import org.springframework.web.reactive.function.client.WebClientResponseException; -import reactor.core.publisher.Mono; - -/** - * Client for communicating with LRS or service which implements some of the xAPI communication - * resources. - * - * @author István Rátkai (Selindek) - * @see xAPI - * communication resources - */ -@Slf4j -public class XapiClient { - - private final WebClient client; - private final ObjectMapper objectMapper; - - /** - * Default constructor for XapiClient. - * - * @param builder a {@link WebClient.Builder} object. The caller must set the baseUrl and the - * authorization header. - * @param objectMapper an {@link ObjectMapper}. It is used for converting {@link Actor} query - * parameters to JSON string during xAPI requests. - */ - public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - this.client = builder - - .defaultHeader("X-Experience-API-Version", "1.0.3") - - .build(); - } - - /** - * Sends an xAPI request. - * - * @param The response type is defined by the request parameter. - * @param request an {@link Request} object describing the xAPI request. - * @return a {@link ResponseEntity} containing the response object defined by the request - * parameter. - */ - public ResponseEntity send(Request request) { - return sendRequest(request, request.getResponseType()); - } - - - public , B extends Request.Builder> ResponseEntity send( - Request.Builder xapiRequest) { - - var request = xapiRequest.build(); - - return sendRequest(request, request.getResponseType()); - - } - - public > ResponseEntity putState( - Consumer> putStateRequest) { - - final PutStateRequest.Builder builder = PutStateRequest.builder(); - - putStateRequest.accept(builder); - - return send(builder); - - } - - - /** - *

- * Convenient type-safe method for sending a {@link GetStateRequest} which expects an instance of - * a given JAVA class as a response. - *

- *

- * The {@link GetStateRequest} is the only xAPI request where the type of the response is not - * defined. Learning Record Providers can store ANY kind of data here. The type conversion of the - * returned state object happens based on the Content-Type header provided when - * the state was stored. If the stored state is incompatible with the - * Content-Type header or it cannot be converted to the expected response type - * then a {@link RuntimeException} is thrown. - *

- *

- * If the generic {@link XapiClient#send(Request)} method is used with {@link GetStateRequest} - * request then the state is returned as a String. - *

- * - * @param The response type is defined by the responseType parameter. - * @param request an {@link GetStateRequest} object. - * @param responseType a {@link Class} object defining the response type of the returning state. - * @return a {@link ResponseEntity} containing the response object . - * @see State - * Resources Description - * @throws RuntimeException when the returned state cannot be converted to the expected JAVA - * class. - */ - public ResponseEntity send(GetStateRequest request, @NonNull Class responseType) { - return sendRequest(request, responseType); - } - - private ResponseEntity sendRequest(Request request, - @NonNull Class responseType) { - - final RequestBodySpec r = client - - .method(request.getMethod()) - - .uri(uriBuilder -> { - final var variableMap = new HashMap(); - request.query(uriBuilder, variableMap); - convertActors(variableMap); - return uriBuilder.path(request.getPath()).build(variableMap); - }) - - //.headers(h -> request.getHttpHeaders()) - ; - - final var body = request.getBody(); - - if (body != null) { - r.bodyValue(body); - } - - return r.retrieve().toEntity(responseType) - - .onErrorResume(WebClientResponseException.class, ex -> { - if (ex.getStatusCode().value() == 404) { - return Mono.just(new ResponseEntity(HttpStatusCode.valueOf(404))); - } - log.warn("Unsuccessful request: ", ex); - log.debug(ex.getResponseBodyAsString()); - return Mono.error(ex); - }) - - .block(); - } - - private void convertActors(HashMap variableMap) { - variableMap.entrySet().stream().filter(s -> s.getValue() instanceof Actor).forEach(s -> { - try { - s.setValue(objectMapper.writeValueAsString(s.getValue())); - } catch (final JsonProcessingException e) { - // Should not happen - } - }); - - } - - -} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java deleted file mode 100644 index 463f383a..00000000 --- a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. - */ - -package dev.learning.xapi.client; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; - -/** - * PutStateRequest Tests. - * - * @author Thomas Turrell-Croft - */ -@DisplayName("PutStateRequest Tests") -class PutStateRequestTests { - - - // activityId | Required - // agent | Required - // registration | Optional - // stateId | Required - - - @Test - void WhenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { - - // When Building PutStateRequest With All Parameters - assertDoesNotThrow(() -> { - var x = PutStateRequest.builder() - - // Parameters - - .activityId("https://example.com/activity/1") - - .agent(a -> a.name("A N Other").mbox("another@example.com")) - - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - - .stateId("bookmark") - - // Body - - .state("Hello World!") - - // Headers - - .contentType(MediaType.TEXT_PLAIN) - - .httpHeaders(null) - - .build(); - - }); - - - - // Then No Exception Is Thrown - - } - - - @Test - void whenDeserializingAboutThenResultIsInstanceOfAbout() { - - // When Building PutStateRequest With All Parameters - assertDoesNotThrow(() -> { - PutStateRequest.builder() - - .activityId("https://example.com/activity/1") - - .agent(a -> a.name("A N Other").mbox("another@example.com")) - - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - - .stateId("bookmark").build(); - }); - - // Then No Exception Is Thrown - - } - - - - @Test - void when() { - - // When Building PutStateRequest With All Parameters - PutStateRequest.builder() - - .activityId("https://example.com/activity/1") - - .agent(a -> a.name("A N Other").mbox("another@example.com")) - - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - - .stateId("bookmark").build(); - - // Then No Exception Is Thrown - - } - - - -} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java b/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java deleted file mode 100644 index 7f2cddd8..00000000 --- a/xapi-client/src/test/java/dev/learning/xapi/client/StateRequestIT.java +++ /dev/null @@ -1,186 +0,0 @@ -package dev.learning.xapi.client; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import dev.learning.xapi.model.Agent; -import java.awt.Point; -import java.net.URI; -import java.util.UUID; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -@SpringBootTest(classes = TestApp.class) -class StateRequestIT { - - @Autowired - private XapiClient client; - - private URI activityId; - private Agent agent; - private String stateId; - private Object state; - private MediaType contentType; - - @BeforeEach - public void init() { - // set some default parameters - activityId = URI.create("http://learning.dev/" + UUID.randomUUID()); - agent = Agent.builder().name("admin").mbox("mailto:admin@learning.dev").build(); - stateId = UUID.randomUUID().toString(); - state = new Point(1, 2); - contentType = MediaType.APPLICATION_JSON; - } - - @Test - void testGivenStateDoesNotExistWhenSendingGetStateRequestThenResponseStatusIsNotFound() { - - // Given State Does Not Exist - - // When Sending GetStateRequest - - final var getRequest = - GetStateRequest.builder().activityId(activityId).agent(agent).stateId(stateId).build(); - final var response = client.send(getRequest); - - // Then Response Status Is Not Found - - assertThat(response.getStatusCode(), is(HttpStatus.NOT_FOUND)); - } - - /* - * - * @Test void testGivenStateExistsWhenSendingGetStateRequestThenResponseBodyIsExpected() { - * - * // Given State Exists state = "text body"; contentType = MediaType.TEXT_PLAIN; - * - * final var putRequest = PutStateRequestTests.builder().activityId(activityId).agent(agent) - * .stateId(stateId).state(state).contentType(contentType).build(); final var putResponse = - * client.send(putRequest); assertThat(putResponse.getStatusCode().value(), is(204)); - * - * // When Sending GetStateRequest - * - * final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) - * .stateId(stateId).build(); final var response = client.send(getRequest); - * - * // Then Response Body Is Expected - * - * assertThat(response.getBody(), is(state)); } - * - * @Test void testGivenStateExistsWhenSendingTypedGetStateRequestThenResponseBodyIsExpected() { - * - * // Given State Exists - * - * final var putRequest = PutStateRequestTests.builder().activityId(activityId).agent(agent) - * .stateId(stateId).state(state).contentType(contentType).build(); final var putResponse = - * client.send(putRequest); assertThat(putResponse.getStatusCode().value(), is(204)); - * - * // When Sending Typed GetStateRequest - * - * final var getRequest = GetStateRequest.builder().activityId(activityId).agent(agent) - * .stateId(stateId).build(); final var response = client.send(getRequest, Point.class); - * - * // Then Response Body Is Expected - * - * assertThat(response.getBody(), is(state)); } - * - * @Test void testGivenMultipleStatesExistsWhenSendingGetStatesRequestThenResponseBodyIsExpected() - * { - * - * // Given Multiple States Exists - * - * final var stateId1 = UUID.randomUUID().toString(); final var stateId2 = - * UUID.randomUUID().toString(); - * - * final var putRequest1 = PutStateRequestTests.builder().activityId(activityId).agent(agent) - * .stateId(stateId1).state(state).contentType(contentType).build(); final var putResponse1 = - * client.send(putRequest1); assertThat(putResponse1.getStatusCode().value(), is(204)); - * - * final var putRequest2 = PutStateRequestTests.builder().activityId(activityId).agent(agent) - * .stateId(stateId2).state(state).contentType(contentType).build(); final var putResponse2 = - * client.send(putRequest2); assertThat(putResponse2.getStatusCode().value(), is(204)); - * - * // When Sending GetStatesRequest - * - * final var getRequest = GetStatesRequest.builder().activityId(activityId).agent(agent).build(); - * final var response = client.send(getRequest); - * - * // Then Response Body Is Expected - * - * assertThat(response.getBody(), allOf(hasItem(stateId1), hasItem(stateId2))); } - * - * - * - * - * - * @Test void test1() { - * - * // Given Multiple States Exists - * - * Agent agent = Agent.builder().name("admin").mbox("mailto:admin@learning.dev").build(); - * - * - * client.putStateRequest(PutStateRequest.builder() - * - * .activityId(URI.create("https://example.com/")) - * - * .agent(agent) - * - * .stateId("resume") - * - * .state(body)); - * - * } - * - * - * @Test void test2() { - * - * client.send(PutStateRequestTests.builder() - * - * .activityId(URI.create("https://example.com/")) - * - * .agent(agent) - * - * .stateId("resume") - * - * .state(state) - * - * .contentType(MediaType.APPLICATION_JSON)); - * - * } - * - * @Test void test3() { - * - * client.putState(r -> r - * - * .activityId("https://example.com/") - * - * .agent(a -> a.mbox("hello").name("world")) - * - * .stateId("resume") - * - * .state(state) - * - * .contentType(MediaType.APPLICATION_JSON)); - * - * } - * - * public void test4() { - * - * PutStateRequestTests.builder() - * - * .activityId("https://example.com/") - * - * .agent(a -> a.mbox("hello").name("world")) - * - * .stateId("resume") - * - * .state(state); - * - * } - */ - -} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java deleted file mode 100644 index 7e95e0f9..00000000 --- a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java +++ /dev/null @@ -1,33 +0,0 @@ -package dev.learning.xapi.client; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpHeaders; -import org.springframework.util.Base64Utils; -import org.springframework.web.reactive.function.client.WebClient; - -import com.fasterxml.jackson.databind.ObjectMapper; - -@SpringBootConfiguration -@EnableAutoConfiguration -public class TestApp { - - @Value("${test.username:admin}") - String username; - - @Value("${test.password:password}") - String password; - - @Value("${test.url:http://localhost:8081/xapi/}") - String url; - - @Bean - public XapiClient xapiClient(WebClient.Builder webClientBuilder, ObjectMapper objectMapper) { - return new XapiClient(webClientBuilder.baseUrl(url) - .defaultHeader(HttpHeaders.AUTHORIZATION, "basic "+ Base64Utils.encodeToString((username+":"+password) - .getBytes())), objectMapper); - } - -} From f4d14c9dea7b537115c714343eda68f3a77c51dd Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 17:02:50 +0000 Subject: [PATCH 25/74] still complies --- .../src/main/java/dev/learning/xapi/client/PutStateRequest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index 56d81db3..5b9dd1b6 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -14,8 +14,6 @@ @SuperBuilder public class PutStateRequest extends PostStateRequest { - - // @Override @Override protected HttpMethod getMethod() { return HttpMethod.PUT; From 7679c900676a6a303e722563e3bbc9afa69f1afb Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 17:06:39 +0000 Subject: [PATCH 26/74] still complies --- .../src/main/java/dev/learning/xapi/client/StatesRequest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 59e84382..62eb139a 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -134,8 +134,6 @@ public B activityId(URI activityId) { } - - /** * Sets the registration. * From 681c518c83c86da881fb3fcb60b8759c1ed5ce2d Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 18:32:41 +0000 Subject: [PATCH 27/74] basic tests on requests --- .../xapi/client/DeleteStateRequestTests.java | 140 ++++++++++++++++++ .../xapi/client/PutStateRequestTests.java | 57 +++++++ 2 files changed, 197 insertions(+) create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java new file mode 100644 index 00000000..55b0f070 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java @@ -0,0 +1,140 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +/** + * DeleteStateRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("DeleteStateRequest Tests") +class DeleteStateRequestTests { + + @Test + void WhenBuildingDeleteStateRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building DeleteStateRequest With All Parameters + assertDoesNotThrow(() -> { + DeleteStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + // Headers + + .build(); + + }); + + // Then No Exception Is Thrown + + } + + @Test + void whenBuildingDeleteStateRequestWithoutRegistrationThenNoExceptionIsThrown() { + + // When Building DeleteStateRequest Without Registration + assertDoesNotThrow(() -> { + DeleteStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .build(); + + }); + + // Then No Exception Is Thrown + + } + + @Test + void whenBuildingDeleteStateRequestWithoutActivityIdThenExceptionIsThrown() { + + + // When Building DeleteStateRequest Without ActivityId + assertThrows(NullPointerException.class, () -> { + DeleteStateRequest.builder() + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + // Headers + + .build(); + + }); + + // Then NullPointerException Is Thrown + + } + + @Test + void whenBuildingDeleteStateRequestWithoutAgentThenExceptionIsThrown() { + + + // When Building DeleteStateRequest Without Agent + assertThrows(NullPointerException.class, () -> { + DeleteStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + // Headers + + .build(); + + }); + + // Then NullPointerException Is Thrown + + } + + @Test + void whenBuildingDeleteStateRequestWithoutStateIdThenExceptionIsThrown() { + + // When Building DeleteStateRequest Without StateId + assertThrows(NullPointerException.class, () -> { + DeleteStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + // Headers + + .build(); + + }); + + // Then NullPointerException Is Thrown + + } + +} + + diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java new file mode 100644 index 00000000..325b8a8b --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * PutStateRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("PutStateRequest Tests") +class PutStateRequestTests { + + + // activityId | Required + // agent | Required + // registration | Optional + // stateId | Required + + + @Test + void whenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building PutStateRequest With All Parameters + assertDoesNotThrow(() -> { + var x = PutStateRequest.builder() + + // Parameters + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + // Body + + .state("Hello World!") + + // Headers + + .build(); + + }); + + // Then No Exception Is Thrown + + } + +} From 85a46d5c70287e62016fffac626e53025fb9c7c6 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 18:36:00 +0000 Subject: [PATCH 28/74] clear test --- .../java/dev/learning/xapi/client/PutStateRequestTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java index 325b8a8b..9679cf8f 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java @@ -28,7 +28,7 @@ void whenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { // When Building PutStateRequest With All Parameters assertDoesNotThrow(() -> { - var x = PutStateRequest.builder() + PutStateRequest.builder() // Parameters From da7e62d6832212d23bbdebafdb84bc34cebd41f4 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 18:57:11 +0000 Subject: [PATCH 29/74] fixed checkstyle --- .../java/dev/learning/xapi/client/Request.java | 17 ++--------------- .../dev/learning/xapi/client/StatesRequest.java | 12 ++++++------ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 7bfa3e71..0ae5e300 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -44,20 +44,6 @@ public Class getResponseType() { */ protected void query(UriBuilder uribuilder, Map variableMap) {} - - - /** - * Callback method which sets the headers for the xAPI request. - * - * @param headers a {@link HttpHeaders} object. - */ - /* - * - * protected void headers(HttpHeaders httpHeaders) { httpHeaders.addAll(this.httpHeaders); - * - * } - */ - /** * The request method. * @@ -83,7 +69,8 @@ protected Object getBody() { - public static abstract class Builder, B extends Request.Builder> { + public abstract static class Builder, + B extends Request.Builder> { } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 62eb139a..875bea29 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -61,23 +61,23 @@ protected void query(UriBuilder uriBuilder, Map variableMap) { variableMap.put("agent", agent); } - public static abstract class Builder, B extends StatesRequest.Builder> - extends Request.Builder { + public abstract static class Builder, + B extends StatesRequest.Builder> extends Request.Builder { /** * Consumer Builder for agent. * - * @param account The Consumer Builder for agent. + * @param agent The Consumer Builder for agent. * * @return This builder * * @see StatesRequest#agent */ - public B agent(Consumer> account) { + public B agent(Consumer> agent) { final Agent.Builder builder = Agent.builder(); - account.accept(builder); + agent.accept(builder); return agent(builder.build()); @@ -86,7 +86,7 @@ public B agent(Consumer> account) { /** * Sets the agent. * - * @param account The Agent of the StatesRequest. + * @param agent The Agent of the StatesRequest. * * @return This builder * From f88cf49f50667afe8d7958082d7e42fa785fa218 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 19:05:08 +0000 Subject: [PATCH 30/74] wip --- xapi-client/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/pom.xml b/xapi-client/pom.xml index a3671ed9..86290a08 100644 --- a/xapi-client/pom.xml +++ b/xapi-client/pom.xml @@ -34,7 +34,7 @@ org.apache.commons commons-lang3 - text + test From d2b291acb8415c9729fc6e43f1d5dfef6d4fc014 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 24 Jan 2023 19:11:59 +0000 Subject: [PATCH 31/74] blar --- .../src/main/java/dev/learning/xapi/client/Request.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 0ae5e300..a7c3e4cb 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -69,10 +69,4 @@ protected Object getBody() { - public abstract static class Builder, - B extends Request.Builder> { - - } - - } From 3bbb20014a49883364358be2d6b0824a61332427 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 26 Jan 2023 15:40:25 +0000 Subject: [PATCH 32/74] assorted rubbish --- .../learning/xapi/client/PutStateRequest.java | 16 +- .../dev/learning/xapi/client/Request.java | 5 +- .../learning/xapi/client/StateRequest.java | 25 +++ .../learning/xapi/client/StatesRequest.java | 16 +- .../dev/learning/xapi/client/XapiClient.java | 189 ++++++++++++++++++ 5 files changed, 242 insertions(+), 9 deletions(-) create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index 5b9dd1b6..b7fb03ae 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -1,5 +1,6 @@ package dev.learning.xapi.client; +import lombok.NonNull; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; @@ -12,10 +13,23 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -public class PutStateRequest extends PostStateRequest { +public class PutStateRequest extends StateRequest { + + /** + * The state object to store. + */ + @NonNull + private final Object state; @Override protected HttpMethod getMethod() { return HttpMethod.PUT; } + + @Override + protected Object getBody() { + + return state; + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index a7c3e4cb..24f2a310 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -1,5 +1,6 @@ package dev.learning.xapi.client; +import java.net.URI; import java.util.Map; import lombok.Builder.Default; import lombok.Getter; @@ -42,7 +43,7 @@ public Class getResponseType() { * @param uribuilder an {@link UriBuilder} object. The methods add query templates to the builder. * @param variableMap a {@link Map} containing the actual values for the query templates. */ - protected void query(UriBuilder uribuilder, Map variableMap) {} + protected abstract URI query(UriBuilder uribuilder, Map variableMap); /** * The request method. @@ -67,6 +68,8 @@ protected Object getBody() { return null; } + // protected abstract URI query(UriBuilder uriBuilder); + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index e2f0ff4c..49175643 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -1,8 +1,12 @@ package dev.learning.xapi.client; +import java.net.URI; +import java.util.Map; +import java.util.Optional; import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; +import org.springframework.web.util.UriBuilder; /** * Abstract superclass for state requests manipulating a single state document. @@ -21,4 +25,25 @@ abstract class StateRequest extends StatesRequest { private final String stateId; + @Override + protected URI query(UriBuilder uriBuilder, Map uriVaribles) { + + // Map variableMap + + return uriBuilder + + .queryParam("activityId", "{activityId}") + + .queryParam("agent", "{agent}") + + .queryParamIfPresent("registration", Optional.ofNullable(registration)) + + .queryParam("stateId", "{stateId}") + + .build(uriVaribles); + + // variableMap.put("activityId", activityId); + // variableMap.put("agent", agent); + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 875bea29..90bf92c3 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -36,11 +36,10 @@ abstract class StatesRequest extends Request { @NonNull private final Agent agent; - // TODO why not final? Because it is Optional? /** * The optional registration query parameter. */ - private UUID registration; + protected final UUID registration; @Override protected String getPath() { @@ -48,17 +47,20 @@ protected String getPath() { } @Override - protected void query(UriBuilder uriBuilder, Map variableMap) { - uriBuilder + protected URI query(UriBuilder uriBuilder, Map uriVaribles) { + + // Map variableMap + + return uriBuilder .queryParam("activityId", "{activityId}") .queryParam("agent", "{agent}") - .queryParamIfPresent("registration", Optional.ofNullable(registration)); + .queryParamIfPresent("registration", Optional.ofNullable(registration)).build(uriVaribles); - variableMap.put("activityId", activityId); - variableMap.put("agent", agent); + // variableMap.put("activityId", activityId); + // variableMap.put("agent", agent); } public abstract static class Builder, diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java new file mode 100644 index 00000000..ad689031 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -0,0 +1,189 @@ +package dev.learning.xapi.client; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import dev.learning.xapi.model.Actor; +import java.util.HashMap; +import java.util.function.Consumer; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; +import org.springframework.web.reactive.function.client.WebClient.UriSpec; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; + +/** + * Client for communicating with LRS or service which implements some of the xAPI communication + * resources. + * + * @author István Rátkai (Selindek) + * @see xAPI + * communication resources + */ +@Slf4j +public class XapiClient { + + private final WebClient client; + private final ObjectMapper objectMapper; + + /** + * Default constructor for XapiClient. + * + * @param builder a {@link WebClient.Builder} object. The caller must set the baseUrl and the + * authorization header. + * @param objectMapper an {@link ObjectMapper}. It is used for converting {@link Actor} query + * parameters to JSON string during xAPI requests. + */ + public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + this.client = builder + + .defaultHeader("X-Experience-API-Version", "1.0.3") + + .build(); + } + + /** + * Sends an xAPI request. + * + * @param The response type is defined by the request parameter. + * @param request an {@link XapiRequest} object describing the xAPI request. + * @return a {@link ResponseEntity} containing the response object defined by the request + * parameter. + */ + public ResponseEntity send(Request request) { + return sendRequest(request, request.getResponseType()); + } + + + // public static abstract class Builder, B extends + // StatesRequest.Builder> extends XapiRequest.Builder { + + + + public > ResponseEntity putState( + PutStateRequest.Builder putStateRequest) { + + var request = putStateRequest.build(); + + return sendRequest(request, request.getResponseType()); + + } + + + + public > ResponseEntity putState( + Consumer> putStateRequest) { + + final PutStateRequest.Builder builder = PutStateRequest.builder(); + + putStateRequest.accept(builder); + + return putState(builder); + + } + + + /* + * public Builder account(Consumer account) { + * + * final Account.Builder builder = Account.builder(); + * + * account.accept(builder); + * + * return account(builder.build()); } + */ + + + + /** + *

+ * Convenient type-safe method for sending a {@link GetStateRequest} which expects an instance of + * a given JAVA class as a response. + *

+ *

+ * The {@link GetStateRequest} is the only xAPI request where the type of the response is not + * defined. Learning Record Providers can store ANY kind of data here. The type conversion of the + * returned state object happens based on the Content-Type header provided when + * the state was stored. If the stored state is incompatible with the + * Content-Type header or it cannot be converted to the expected response type + * then a {@link RuntimeException} is thrown. + *

+ *

+ * If the generic {@link XapiClient#send(XapiRequest)} method is used with {@link GetStateRequest} + * request then the state is returned as a String. + *

+ * + * @param The response type is defined by the responseType parameter. + * @param request an {@link GetStateRequest} object. + * @param responseType a {@link Class} object defining the response type of the returning state. + * @return a {@link ResponseEntity} containing the response object . + * @see State + * Resources Description + * @throws RuntimeException when the returned state cannot be converted to the expected JAVA + * class. + */ + public ResponseEntity send(GetStateRequest request, @NonNull Class responseType) { + return sendRequest(request, responseType); + } + + private ResponseEntity sendRequest(Request request, @NonNull Class responseType) { + + UriSpec uriSpec = client.method(request.getMethod()); + + RequestBodySpec bodySpec = + uriSpec.uri(uriBuilder -> request.query(uriBuilder, new HashMap())); + + final RequestBodySpec r = client + + .method(request.getMethod()) + + .uri(uriBuilder -> { + // final var variableMap = new HashMap(); + // request.query(uriBuilder, variableMap); + // convertActors(variableMap); + return uriBuilder.path(request.getPath()).build(variableMap); + }) + + .headers(request::headers); + + final var body = request.getBody(); + + if (body != null) { + r.bodyValue(body); + } + + return r.retrieve().toEntity(responseType) + + .onErrorResume(WebClientResponseException.class, ex -> { + if (ex.getStatusCode().value() == 404) { + return Mono.just(new ResponseEntity(HttpStatusCode.valueOf(404))); + } + log.warn("Unsuccessful request: ", ex); + log.debug(ex.getResponseBodyAsString()); + return Mono.error(ex); + }) + + .block(); + } + + private void convertActors(HashMap variableMap) { + variableMap.entrySet().stream().filter(s -> s.getValue() instanceof Actor).forEach(s -> { + try { + s.setValue(objectMapper.writeValueAsString(s.getValue())); + } catch (final JsonProcessingException e) { + // Should not happen + } + }); + + } + + +} From 0621e5a31256bee590e6da5baeb3d0ebb1c817b3 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 27 Jan 2023 15:13:10 +0000 Subject: [PATCH 33/74] wip --- .../dev/learning/xapi/client/Request.java | 28 +---- .../learning/xapi/client/StateRequest.java | 22 +--- .../learning/xapi/client/StatesRequest.java | 72 ++++++++--- .../dev/learning/xapi/client/XapiClient.java | 31 ++--- .../xapi/client/DeleteStateRequestTests.java | 112 +++++++++--------- .../xapi/client/GetStateRequestTests.java | 40 +++++++ .../xapi/client/PostStateRequestTests.java | 57 +++++++++ 7 files changed, 224 insertions(+), 138 deletions(-) create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 24f2a310..62fa2782 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -1,14 +1,10 @@ package dev.learning.xapi.client; -import java.net.URI; -import java.util.Map; -import lombok.Builder.Default; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.experimental.SuperBuilder; import org.springframework.core.GenericTypeResolver; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.util.Assert; import org.springframework.web.util.UriBuilder; @@ -24,26 +20,17 @@ @RequiredArgsConstructor abstract class Request { - @NonNull - @Default - private final HttpHeaders httpHeaders = new HttpHeaders(); - @NonNull @SuppressWarnings("unchecked") public Class getResponseType() { + final var responseType = (Class) GenericTypeResolver.resolveTypeArgument(getClass(), Request.class); Assert.notNull(responseType, "XapiRequest resolved generic type must not be null"); return responseType; } - /** - * Callback method which sets the query parameters for the xAPI request. - * - * @param uribuilder an {@link UriBuilder} object. The methods add query templates to the builder. - * @param variableMap a {@link Map} containing the actual values for the query templates. - */ - protected abstract URI query(UriBuilder uribuilder, Map variableMap); + protected abstract UriBuilder url(UriBuilder uriBuilder); /** * The request method. @@ -52,13 +39,6 @@ public Class getResponseType() { */ protected abstract HttpMethod getMethod(); - /** - * The path of the request endpoint. - * - * @return the path of the request endpoint as a String. - */ - protected abstract String getPath(); - /** * The request body. Default is null * @@ -68,8 +48,4 @@ protected Object getBody() { return null; } - // protected abstract URI query(UriBuilder uriBuilder); - - - } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index 49175643..ddadac9e 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -1,8 +1,5 @@ package dev.learning.xapi.client; -import java.net.URI; -import java.util.Map; -import java.util.Optional; import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; @@ -24,26 +21,11 @@ abstract class StateRequest extends StatesRequest { @NonNull private final String stateId; - @Override - protected URI query(UriBuilder uriBuilder, Map uriVaribles) { - - // Map variableMap - - return uriBuilder - - .queryParam("activityId", "{activityId}") - - .queryParam("agent", "{agent}") - - .queryParamIfPresent("registration", Optional.ofNullable(registration)) - - .queryParam("stateId", "{stateId}") + protected UriBuilder url(UriBuilder uriBuilder) { - .build(uriVaribles); + return super.url(uriBuilder).queryParam("stateId", stateId); - // variableMap.put("activityId", activityId); - // variableMap.put("agent", agent); } } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 90bf92c3..e9433c7b 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -1,8 +1,9 @@ package dev.learning.xapi.client; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import dev.learning.xapi.model.Agent; import java.net.URI; -import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; @@ -10,6 +11,7 @@ import lombok.NonNull; import lombok.experimental.SuperBuilder; import org.springframework.web.util.UriBuilder; +import org.springframework.web.util.UriComponentsBuilder; /** * Abstract superclass of xAPI state resource request. @@ -24,6 +26,8 @@ @Getter abstract class StatesRequest extends Request { + private final ObjectMapper objectMapper = new ObjectMapper(); + /** * The activityId query parameter. */ @@ -39,30 +43,67 @@ abstract class StatesRequest extends Request { /** * The optional registration query parameter. */ - protected final UUID registration; + private final UUID registration; + + /* + * @Override protected UriBuilder url(UriBuilder uriBuilder) { + * + * HashMap map = new HashMap<>(); map.put("activityId", activityId); + * map.put("agent", agentToJsonString()); + * + * URI uri = uriBuilder.path("activities/state") + * + * .queryParam("activityId", "{activityId}") + * + * .queryParam("agent", "{agent}") + * + * .queryParamIfPresent("registration", Optional.ofNullable(registration)).build(map); + * + * return UriComponentsBuilder.fromUri(uri); + * + * } + */ + - @Override - protected String getPath() { - return "activities/state"; - } @Override - protected URI query(UriBuilder uriBuilder, Map uriVaribles) { + protected UriBuilder url(UriBuilder uriBuilder) { + + // map.put("agent", agentToJsonString()); + + // encodingMode + + System.out.println("Hello class " + uriBuilder.getClass()); + + UriComponentsBuilder bob = (UriComponentsBuilder) uriBuilder; + - // Map variableMap + return bob.path("activities/state") - return uriBuilder + .queryParam("activityId", activityId) - .queryParam("activityId", "{activityId}") + .queryParam("agent", + "{\"objectType\":\"Agent\",\"name\":\"A N Other\",\"mbox\":\"another@example.com\"}") - .queryParam("agent", "{agent}") + .queryParamIfPresent("registration", Optional.ofNullable(registration)); + } + + + public String agentToJsonString() { + + try { + + System.out.println("agent to json " + objectMapper.writeValueAsString(agent)); - .queryParamIfPresent("registration", Optional.ofNullable(registration)).build(uriVaribles); + return objectMapper.writeValueAsString(agent); + } catch (JsonProcessingException e) { + // Should not happen + } - // variableMap.put("activityId", activityId); - // variableMap.put("agent", agent); + return null; } + public abstract static class Builder, B extends StatesRequest.Builder> extends Request.Builder { @@ -170,9 +211,6 @@ public B registration(UUID registration) { } - - } - } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index ad689031..e7b1b980 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -7,6 +7,7 @@ import java.util.function.Consumer; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; @@ -90,17 +91,6 @@ B extends PutStateRequest.Builder> ResponseEntity putState( } - /* - * public Builder account(Consumer account) { - * - * final Account.Builder builder = Account.builder(); - * - * account.accept(builder); - * - * return account(builder.build()); } - */ - - /** *

@@ -138,21 +128,22 @@ private ResponseEntity sendRequest(Request request, @NonNull Class UriSpec uriSpec = client.method(request.getMethod()); - RequestBodySpec bodySpec = - uriSpec.uri(uriBuilder -> request.query(uriBuilder, new HashMap())); + RequestBodySpec bodySpec = uriSpec.uri(uriBuilder -> request.url(uriBuilder).build()); + + + + // RequestHeadersSpec headersSpec = bodySpec.h + + // ResponseSpec responseSpec = headersSpec.header + final RequestBodySpec r = client .method(request.getMethod()) - .uri(uriBuilder -> { - // final var variableMap = new HashMap(); - // request.query(uriBuilder, variableMap); - // convertActors(variableMap); - return uriBuilder.path(request.getPath()).build(variableMap); - }) + .uri(uriBuilder -> request.url(uriBuilder).build()) - .headers(request::headers); + .headers(headers -> new HttpHeaders()); final var body = request.getBody(); diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java index 55b0f070..407cc7ca 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java @@ -4,11 +4,17 @@ package dev.learning.xapi.client; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; +import dev.learning.xapi.client.DeleteStateRequest.Builder; +import java.net.URI; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; - +import org.springframework.web.util.UriBuilder; +import org.springframework.web.util.UriComponentsBuilder; /** * DeleteStateRequest Tests. @@ -19,27 +25,21 @@ class DeleteStateRequestTests { @Test - void WhenBuildingDeleteStateRequestWithAllParametersThenNoExceptionIsThrown() { + void whenBuildingDeleteStateRequestWithAllParametersThenNoExceptionIsThrown() { // When Building DeleteStateRequest With All Parameters - assertDoesNotThrow(() -> { - DeleteStateRequest.builder() - - .activityId("https://example.com/activity/1") - - .agent(a -> a.name("A N Other").mbox("another@example.com")) + Builder builder = DeleteStateRequest.builder() - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + .activityId("https://example.com/activity/1") - .stateId("bookmark") + .agent(a -> a.name("A N Other").mbox("another@example.com")) - // Headers + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .build(); - - }); + .stateId("bookmark"); // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); } @@ -47,91 +47,93 @@ void WhenBuildingDeleteStateRequestWithAllParametersThenNoExceptionIsThrown() { void whenBuildingDeleteStateRequestWithoutRegistrationThenNoExceptionIsThrown() { // When Building DeleteStateRequest Without Registration - assertDoesNotThrow(() -> { - DeleteStateRequest.builder() - - .activityId("https://example.com/activity/1") - - .agent(a -> a.name("A N Other").mbox("another@example.com")) + Builder builder = DeleteStateRequest.builder() - .stateId("bookmark") + .activityId("https://example.com/activity/1") - .build(); + .agent(a -> a.name("A N Other").mbox("another@example.com")) - }); + .stateId("bookmark"); // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); } @Test void whenBuildingDeleteStateRequestWithoutActivityIdThenExceptionIsThrown() { - // When Building DeleteStateRequest Without ActivityId - assertThrows(NullPointerException.class, () -> { - DeleteStateRequest.builder() - - .agent(a -> a.name("A N Other").mbox("another@example.com")) - - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + Builder builder = DeleteStateRequest.builder() - .stateId("bookmark") + .agent(a -> a.name("A N Other").mbox("another@example.com")) - // Headers + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .build(); - - }); + .stateId("bookmark"); // Then NullPointerException Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); } @Test void whenBuildingDeleteStateRequestWithoutAgentThenExceptionIsThrown() { - // When Building DeleteStateRequest Without Agent - assertThrows(NullPointerException.class, () -> { - DeleteStateRequest.builder() + Builder builder = DeleteStateRequest.builder() - .activityId("https://example.com/activity/1") + .activityId("https://example.com/activity/1") - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark") + .stateId("bookmark"); - // Headers + // Then NullPointerException Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); - .build(); + } + + @Test + void whenBuildingDeleteStateRequestWithoutStateIdThenExceptionIsThrown() { + + // When Building DeleteStateRequest Without StateId + Builder builder = DeleteStateRequest.builder() - }); + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6"); // Then NullPointerException Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); } @Test - void whenBuildingDeleteStateRequestWithoutStateIdThenExceptionIsThrown() { + void When() { - // When Building DeleteStateRequest Without StateId - assertThrows(NullPointerException.class, () -> { - DeleteStateRequest.builder() + UriBuilder builder = UriComponentsBuilder.fromUriString("https://example.com/xapi/"); - .activityId("https://example.com/activity/1") + // When + DeleteStateRequest request = DeleteStateRequest.builder() - .agent(a -> a.name("A N Other").mbox("another@example.com")) + .activityId("https://example.com/activity/1") - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + .agent(a -> a.name("A N Other").mbox("another@example.com")) - // Headers + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .build(); + .stateId("bookmark") - }); + .build(); - // Then NullPointerException Is Thrown + URI url = ((UriComponentsBuilder) (request.url(builder))).build().encode().toUri(); + + // Then + assertThat(url, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https://example.com/activity/1&agent=%7B%22objectType%22:%22Agent%22,%22name%22:%22A%20N%20Other%22,%22mbox%22:%22another@example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java new file mode 100644 index 00000000..939e78e3 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java @@ -0,0 +1,40 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import dev.learning.xapi.client.GetStateRequest.Builder; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * GetStateRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("GetStateRequest Tests") +class GetStateRequestTests { + + @Test + void whenBuildingGetStateRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building GetStateRequest With All Parameters + Builder builder = GetStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark"); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + + } + +} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java new file mode 100644 index 00000000..0f9edd78 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * PutStateRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("PostStateRequest Tests") +class PostStateRequestTests { + + + // activityId | Required + // agent | Required + // registration | Optional + // stateId | Required + + + @Test + void whenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building PutStateRequest With All Parameters + assertDoesNotThrow(() -> { + PutStateRequest.builder() + + // Parameters + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + // Body + + .state("Hello World!") + + // Headers + + .build(); + + }); + + // Then No Exception Is Thrown + + } + +} From ca42b59d5d70bd5087e5bd820557980809fb8811 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 27 Jan 2023 18:40:42 +0000 Subject: [PATCH 34/74] sort of ok --- .../dev/learning/xapi/client/Request.java | 3 +- .../learning/xapi/client/StateRequest.java | 7 +- .../learning/xapi/client/StatesRequest.java | 21 ++-- .../dev/learning/xapi/client/XapiClient.java | 22 +--- .../xapi/client/DeleteStateRequestTests.java | 8 +- .../xapi/client/DeleteStatesRequestTests.java | 115 ++++++++++++++++++ 6 files changed, 140 insertions(+), 36 deletions(-) create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 62fa2782..40b9aeb3 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -1,5 +1,6 @@ package dev.learning.xapi.client; +import java.util.Map; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -30,7 +31,7 @@ public Class getResponseType() { return responseType; } - protected abstract UriBuilder url(UriBuilder uriBuilder); + protected abstract UriBuilder url(UriBuilder uriBuilder, Map queryParams); /** * The request method. diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index ddadac9e..397160c5 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -1,5 +1,6 @@ package dev.learning.xapi.client; +import java.util.Map; import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; @@ -22,9 +23,11 @@ abstract class StateRequest extends StatesRequest { private final String stateId; @Override - protected UriBuilder url(UriBuilder uriBuilder) { + protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) { - return super.url(uriBuilder).queryParam("stateId", stateId); + queryParams.put("stateId", stateId); + + return super.url(uriBuilder, queryParams).queryParam("stateId", "{stateId}"); } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index e9433c7b..2bb4379f 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import dev.learning.xapi.model.Agent; import java.net.URI; +import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; @@ -11,7 +12,6 @@ import lombok.NonNull; import lombok.experimental.SuperBuilder; import org.springframework.web.util.UriBuilder; -import org.springframework.web.util.UriComponentsBuilder; /** * Abstract superclass of xAPI state resource request. @@ -67,23 +67,16 @@ abstract class StatesRequest extends Request { @Override - protected UriBuilder url(UriBuilder uriBuilder) { + protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) { - // map.put("agent", agentToJsonString()); + queryParams.put("activityId", activityId); + queryParams.put("agent", agentToJsonString()); - // encodingMode + return uriBuilder.path("activities/state") - System.out.println("Hello class " + uriBuilder.getClass()); + .queryParam("activityId", "{activityId}") - UriComponentsBuilder bob = (UriComponentsBuilder) uriBuilder; - - - return bob.path("activities/state") - - .queryParam("activityId", activityId) - - .queryParam("agent", - "{\"objectType\":\"Agent\",\"name\":\"A N Other\",\"mbox\":\"another@example.com\"}") + .queryParam("agent", "{agent}") .queryParamIfPresent("registration", Optional.ofNullable(registration)); } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index e7b1b980..376bbead 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -1,9 +1,9 @@ package dev.learning.xapi.client; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import dev.learning.xapi.model.Actor; import java.util.HashMap; +import java.util.Map; import java.util.function.Consumer; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -12,7 +12,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; -import org.springframework.web.reactive.function.client.WebClient.UriSpec; import org.springframework.web.reactive.function.client.WebClientResponseException; import reactor.core.publisher.Mono; @@ -126,22 +125,21 @@ public ResponseEntity send(GetStateRequest request, @NonNull Class res private ResponseEntity sendRequest(Request request, @NonNull Class responseType) { - UriSpec uriSpec = client.method(request.getMethod()); - - RequestBodySpec bodySpec = uriSpec.uri(uriBuilder -> request.url(uriBuilder).build()); - + // UriSpec uriSpec = client.method(request.getMethod()); + // RequestBodySpec bodySpec = uriSpec.uri(uriBuilder -> request.url(uriBuilder).build()); // RequestHeadersSpec headersSpec = bodySpec.h // ResponseSpec responseSpec = headersSpec.header + Map queryParams = new HashMap<>(); final RequestBodySpec r = client .method(request.getMethod()) - .uri(uriBuilder -> request.url(uriBuilder).build()) + .uri(uriBuilder -> request.url(uriBuilder, queryParams).build(queryParams)) .headers(headers -> new HttpHeaders()); @@ -165,16 +163,6 @@ private ResponseEntity sendRequest(Request request, @NonNull Class .block(); } - private void convertActors(HashMap variableMap) { - variableMap.entrySet().stream().filter(s -> s.getValue() instanceof Actor).forEach(s -> { - try { - s.setValue(objectMapper.writeValueAsString(s.getValue())); - } catch (final JsonProcessingException e) { - // Should not happen - } - }); - - } } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java index 407cc7ca..52011d41 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java @@ -11,6 +11,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import dev.learning.xapi.client.DeleteStateRequest.Builder; import java.net.URI; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.web.util.UriBuilder; @@ -129,11 +131,13 @@ void When() { .build(); - URI url = ((UriComponentsBuilder) (request.url(builder))).build().encode().toUri(); + Map queryParams = new HashMap<>(); + + URI url = request.url(builder, queryParams).build(queryParams); // Then assertThat(url, is(URI.create( - "https://example.com/xapi/activities/state?activityId=https://example.com/activity/1&agent=%7B%22objectType%22:%22Agent%22,%22name%22:%22A%20N%20Other%22,%22mbox%22:%22another@example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java new file mode 100644 index 00000000..5af50b35 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ +package dev.learning.xapi.client; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import dev.learning.xapi.client.DeleteStatesRequest.Builder; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.web.util.UriBuilder; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * DeleteStatesRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("DeleteStatesRequest Tests") +class DeleteStatesRequestTests { + + @Test + void whenBuildingDeleteStatesRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building DeleteStatesRequest With All Parameters + Builder builder = DeleteStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6"); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + + @Test + void whenBuildingDeleteStatesRequestWithoutRegistrationThenNoExceptionIsThrown() { + + // When Building DeleteStatesRequest Without Registration + Builder builder = DeleteStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + + @Test + void whenBuildingDeleteStatesRequestWithoutActivityIdThenExceptionIsThrown() { + + // When Building DeleteStatesRequest Without ActivityId + Builder builder = DeleteStatesRequest.builder() + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6"); + + // Then NullPointerException Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); + + } + + @Test + void whenBuildingDeleteStatesRequestWithoutAgentThenExceptionIsThrown() { + + // When Building DeleteStatesRequest Without Agent + Builder builder = DeleteStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6"); + + // Then NullPointerException Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); + + } + + @Test + void when() { + + UriBuilder builder = UriComponentsBuilder.fromUriString("https://example.com/xapi/"); + + // When + DeleteStatesRequest request = DeleteStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .build(); + + Map queryParams = new HashMap<>(); + + URI url = request.url(builder, queryParams).build(queryParams); + + // Then + assertThat(url, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6"))); + + } + +} From 0fe0198efa386451a85b8dea3d4b252a83461b86 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 27 Jan 2023 18:42:53 +0000 Subject: [PATCH 35/74] tip --- .../xapi/client/GetStatesRequestTests.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java new file mode 100644 index 00000000..aedafe02 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java @@ -0,0 +1,38 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import dev.learning.xapi.client.GetStatesRequest.Builder; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * GetStatesRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("GetStatesRequest Tests") +class GetStatesRequestTests { + + @Test + void whenBuildingGetStatesRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building GetStatesRequest With All Parameters + Builder builder = GetStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6"); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + + } + +} From 14f7cd3a22cbb9f9735c0f3266e7b142f37e08f9 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 30 Jan 2023 14:28:29 +0000 Subject: [PATCH 36/74] top --- .../learning/xapi/client/StatesRequest.java | 26 +------------------ .../dev/learning/xapi/client/XapiClient.java | 6 +---- .../xapi/client/PostStateRequestTests.java | 7 ----- 3 files changed, 2 insertions(+), 37 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 2bb4379f..0a872a27 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -45,27 +45,6 @@ abstract class StatesRequest extends Request { */ private final UUID registration; - /* - * @Override protected UriBuilder url(UriBuilder uriBuilder) { - * - * HashMap map = new HashMap<>(); map.put("activityId", activityId); - * map.put("agent", agentToJsonString()); - * - * URI uri = uriBuilder.path("activities/state") - * - * .queryParam("activityId", "{activityId}") - * - * .queryParam("agent", "{agent}") - * - * .queryParamIfPresent("registration", Optional.ofNullable(registration)).build(map); - * - * return UriComponentsBuilder.fromUri(uri); - * - * } - */ - - - @Override protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) { @@ -85,15 +64,12 @@ protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) public String agentToJsonString() { try { - - System.out.println("agent to json " + objectMapper.writeValueAsString(agent)); - return objectMapper.writeValueAsString(agent); } catch (JsonProcessingException e) { // Should not happen + return null; } - return null; } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 376bbead..949f5cc6 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -28,7 +28,6 @@ public class XapiClient { private final WebClient client; - private final ObjectMapper objectMapper; /** * Default constructor for XapiClient. @@ -38,8 +37,7 @@ public class XapiClient { * @param objectMapper an {@link ObjectMapper}. It is used for converting {@link Actor} query * parameters to JSON string during xAPI requests. */ - public XapiClient(WebClient.Builder builder, ObjectMapper objectMapper) { - this.objectMapper = objectMapper; + public XapiClient(WebClient.Builder builder) { this.client = builder .defaultHeader("X-Experience-API-Version", "1.0.3") @@ -75,8 +73,6 @@ B extends PutStateRequest.Builder> ResponseEntity putState( } - - public > ResponseEntity putState( Consumer> putStateRequest) { diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java index 0f9edd78..85b24044 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java @@ -16,13 +16,6 @@ @DisplayName("PostStateRequest Tests") class PostStateRequestTests { - - // activityId | Required - // agent | Required - // registration | Optional - // stateId | Required - - @Test void whenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { From f4849ff1b355b50e9f63434d9a8312190b1fcea9 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 30 Jan 2023 17:53:29 +0000 Subject: [PATCH 37/74] closer --- .../learning/xapi/client/GetStateRequest.java | 3 +- .../xapi/client/GetStatesRequest.java | 19 ++- .../dev/learning/xapi/client/XapiClient.java | 68 ++++++++--- .../xapi/client/GetStateRequestTests.java | 2 +- .../learning/xapi/client/XapiClientTests.java | 112 ++++++++++++++++++ 5 files changed, 186 insertions(+), 18 deletions(-) create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index f1f9a5cc..7c399b14 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -10,9 +10,10 @@ * "https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#single-document-put--post--get--delete">Single * State Document GET * @author István Rátkai (Selindek) + * @param */ @SuperBuilder -public class GetStateRequest extends StateRequest { +public class GetStateRequest extends StateRequest { @Override protected HttpMethod getMethod() { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index e9de05c0..609ba888 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -1,8 +1,13 @@ package dev.learning.xapi.client; +import java.time.Instant; import java.util.List; +import java.util.Map; +import java.util.Optional; +import lombok.Getter; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; +import org.springframework.web.util.UriBuilder; /** * Request for getting multiple State documents. @@ -11,13 +16,25 @@ * "https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#multiple-document-get">Multiple * State Document GET * @author István Rátkai (Selindek) + * @param */ @SuperBuilder -public class GetStatesRequest extends StatesRequest> { +@Getter +public class GetStatesRequest extends StatesRequest> { + + private final Instant since; @Override protected HttpMethod getMethod() { return HttpMethod.GET; } + @Override + protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + + return super.url(uriBuilder, queryParams).queryParamIfPresent("since", + Optional.ofNullable(since)); + + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 949f5cc6..045d3118 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -45,6 +45,8 @@ public XapiClient(WebClient.Builder builder) { .build(); } + + /** * Sends an xAPI request. * @@ -53,40 +55,76 @@ public XapiClient(WebClient.Builder builder) { * @return a {@link ResponseEntity} containing the response object defined by the request * parameter. */ - public ResponseEntity send(Request request) { - return sendRequest(request, request.getResponseType()); + /* + * public ResponseEntity send(Request request) { + * + * return sendRequest(request, request.getResponseType()); } + */ + + public > ResponseEntity putState( + Consumer> putStateRequest) { + + final PutStateRequest.Builder builder = PutStateRequest.builder(); + + putStateRequest.accept(builder); + + return send(builder); } - // public static abstract class Builder, B extends - // StatesRequest.Builder> extends XapiRequest.Builder { + public > ResponseEntity postState( + Consumer> postStateRequest) { + final PostStateRequest.Builder builder = PostStateRequest.builder(); - public > ResponseEntity putState( - PutStateRequest.Builder putStateRequest) { + postStateRequest.accept(builder); - var request = putStateRequest.build(); + return send(builder); + + } - return sendRequest(request, request.getResponseType()); + + + public > ResponseEntity deleteState( + Consumer> deleteStateRequest) { + + final DeleteStateRequest.Builder builder = DeleteStateRequest.builder(); + + deleteStateRequest.accept(builder); + + return send(builder); } - public > ResponseEntity putState( - Consumer> putStateRequest) { - final PutStateRequest.Builder builder = PutStateRequest.builder(); + public > ResponseEntity deleteStates( + Consumer> deleteStatesRequest) { - putStateRequest.accept(builder); + final DeleteStatesRequest.Builder builder = DeleteStatesRequest.builder(); + + deleteStatesRequest.accept(builder); - return putState(builder); + return send(builder); } + private , B extends Request.Builder, + T> ResponseEntity send(Request.Builder builder) { + + var request = builder.build(); + + return sendRequest(request, request.getResponseType()); + + } + + /** *

* Convenient type-safe method for sending a {@link GetStateRequest} which expects an instance of diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java index 939e78e3..5000f9a3 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java @@ -21,7 +21,7 @@ class GetStateRequestTests { void whenBuildingGetStateRequestWithAllParametersThenNoExceptionIsThrown() { // When Building GetStateRequest With All Parameters - Builder builder = GetStateRequest.builder() + Builder builder = GetStateRequest.builder() .activityId("https://example.com/activity/1") diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java new file mode 100644 index 00000000..b69bdcc2 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * DeleteStateRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("DeleteStateRequest Tests") +class XapiClientTests { + + + XapiClient client = new XapiClient(null); + + @Test + void deleteState() { + + client.deleteState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark")); + + } + + @Test + void deleteStates() { + + client.deleteStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + ); + + } + + @Test + void putState() { + + client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello") + + ); + + } + + @Test + void postState() { + + client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello") + + ); + + } + + @Test + void getState() { + + client.getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark")); + + } + + @Test + void getStates() { + + client.getStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .since(null) + + ); + + } + +} + + From fef09451a9e5ed2df3474f48e3723da4994d833c Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 30 Jan 2023 22:37:42 +0000 Subject: [PATCH 38/74] tip --- .../dev/learning/xapi/client/XapiClient.java | 28 ++++++++++++++++++- .../learning/xapi/client/XapiClientTests.java | 3 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 045d3118..2ed01ddf 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import dev.learning.xapi.model.Actor; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Consumer; import lombok.NonNull; @@ -115,6 +116,31 @@ B extends DeleteStatesRequest.Builder> ResponseEntity deleteStates( + public , B extends GetStateRequest.Builder, + T> ResponseEntity getState(Consumer> getStateRequest) { + + final GetStateRequest.Builder builder = GetStateRequest.builder(); + + getStateRequest.accept(builder); + + return send(builder); + + } + + public >, B extends GetStatesRequest.Builder, C, B>, + T> ResponseEntity getStates( + Consumer, ?, ?>> getStatesRequest) { + + final GetStatesRequest.Builder, ?, ?> builder = GetStatesRequest.builder(); + + getStatesRequest.accept(builder); + + return send(builder); + + } + + + private , B extends Request.Builder, T> ResponseEntity send(Request.Builder builder) { @@ -153,7 +179,7 @@ T> ResponseEntity send(Request.Builder builder) { * @throws RuntimeException when the returned state cannot be converted to the expected JAVA * class. */ - public ResponseEntity send(GetStateRequest request, @NonNull Class responseType) { + public ResponseEntity send(GetStateRequest request, @NonNull Class responseType) { return sendRequest(request, responseType); } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index b69bdcc2..46c683f0 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -5,6 +5,7 @@ package dev.learning.xapi.client; +import java.time.Instant; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -101,7 +102,7 @@ void getStates() { .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .since(null) + .since(Instant.parse("2023-01-30T22:27:09Z")) ); From 1759a781c94c8223bcf01799cce555839ce62894 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 31 Jan 2023 15:56:25 +0000 Subject: [PATCH 39/74] tidy --- .../main/java/dev/learning/xapi/client/PostStateRequest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index ded21e2f..9b6fec84 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -1,6 +1,5 @@ package dev.learning.xapi.client; -import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; @@ -17,7 +16,6 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -@Getter public class PostStateRequest extends StateRequest { /** From 9a18cbd19be5f86d11c907e1960e66a1b4b46326 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 2 Feb 2023 11:40:30 +0000 Subject: [PATCH 40/74] bosh --- .../java/dev/learning/xapi/client/XapiClient.java | 13 ++++++++++--- .../dev/learning/xapi/client/XapiClientTests.java | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 2ed01ddf..6afa5bae 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -28,7 +28,7 @@ @Slf4j public class XapiClient { - private final WebClient client; + private final WebClient webClient; /** * Default constructor for XapiClient. @@ -39,7 +39,7 @@ public class XapiClient { * parameters to JSON string during xAPI requests. */ public XapiClient(WebClient.Builder builder) { - this.client = builder + this.webClient = builder .defaultHeader("X-Experience-API-Version", "1.0.3") @@ -183,8 +183,15 @@ public ResponseEntity send(GetStateRequest request, @NonNull Class return sendRequest(request, responseType); } + + public Mono

someRestCall(String name) { + return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class); + } + private ResponseEntity sendRequest(Request request, @NonNull Class responseType) { + + // UriSpec uriSpec = client.method(request.getMethod()); // RequestBodySpec bodySpec = uriSpec.uri(uriBuilder -> request.url(uriBuilder).build()); @@ -195,7 +202,7 @@ private ResponseEntity sendRequest(Request request, @NonNull Class Map queryParams = new HashMap<>(); - final RequestBodySpec r = client + final RequestBodySpec r = webClient .method(request.getMethod()) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index 46c683f0..6c1b8cba 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -8,6 +8,7 @@ import java.time.Instant; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.http.ResponseEntity; /** * DeleteStateRequest Tests. @@ -23,7 +24,7 @@ class XapiClientTests { @Test void deleteState() { - client.deleteState(r -> r.activityId("https://example.com/activity/1") + ResponseEntity t = client.deleteState(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) @@ -31,6 +32,8 @@ void deleteState() { .stateId("bookmark")); + + } @Test From 55027f721470759056af486e9d0b67bdb1cfc35a Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 3 Feb 2023 12:59:05 +0000 Subject: [PATCH 41/74] tip --- xapi-client/pom.xml | 20 +- .../dev/learning/xapi/client/Request.java | 21 -- .../dev/learning/xapi/client/XapiClient.java | 210 +++++------------- .../dev/learning/xapi/client/TestApp.java | 11 + .../learning/xapi/client/XapiClientTests.java | 183 ++++++++++++--- .../java/dev/learning/xapi/model/Score.java | 2 +- 6 files changed, 232 insertions(+), 215 deletions(-) create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java diff --git a/xapi-client/pom.xml b/xapi-client/pom.xml index 86290a08..cb7e5f23 100644 --- a/xapi-client/pom.xml +++ b/xapi-client/pom.xml @@ -6,12 +6,9 @@ xapi-build 1.0.1-SNAPSHOT - xapi-client - xAPI Client learning.dev xAPI Client - org.springframework.boot @@ -31,13 +28,27 @@ spring-boot-starter-test test + + com.squareup.okhttp3 + mockwebserver + test + + + com.squareup.okhttp3 + okhttp + test + org.apache.commons commons-lang3 test + + io.netty + netty-resolver-dns-native-macos + osx-aarch_64 + - @@ -46,5 +57,4 @@ - diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 40b9aeb3..38c3e141 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -2,12 +2,9 @@ import java.util.Map; import lombok.Getter; -import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.experimental.SuperBuilder; -import org.springframework.core.GenericTypeResolver; import org.springframework.http.HttpMethod; -import org.springframework.util.Assert; import org.springframework.web.util.UriBuilder; /** @@ -21,16 +18,6 @@ @RequiredArgsConstructor abstract class Request { - @NonNull - @SuppressWarnings("unchecked") - public Class getResponseType() { - - final var responseType = - (Class) GenericTypeResolver.resolveTypeArgument(getClass(), Request.class); - Assert.notNull(responseType, "XapiRequest resolved generic type must not be null"); - return responseType; - } - protected abstract UriBuilder url(UriBuilder uriBuilder, Map queryParams); /** @@ -40,13 +27,5 @@ public Class getResponseType() { */ protected abstract HttpMethod getMethod(); - /** - * The request body. Default is null - * - * @return the request body. - */ - protected Object getBody() { - return null; - } } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 6afa5bae..9bef01ad 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -3,17 +3,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import dev.learning.xapi.model.Actor; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.function.Consumer; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; -import org.springframework.web.reactive.function.client.WebClientResponseException; import reactor.core.publisher.Mono; /** @@ -25,7 +18,6 @@ * "https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#20-resources">xAPI * communication resources */ -@Slf4j public class XapiClient { private final WebClient webClient; @@ -46,188 +38,96 @@ public XapiClient(WebClient.Builder builder) { .build(); } - - /** - * Sends an xAPI request. + * Deletes a single document specified by the given stateId activity, agent, and optional + * registration. * - * @param The response type is defined by the request parameter. - * @param request an {@link XapiRequest} object describing the xAPI request. - * @return a {@link ResponseEntity} containing the response object defined by the request - * parameter. - */ - /* - * public ResponseEntity send(Request request) { + * The returned ResponseEntity contains the response headers. + * + * @param request The parameters of the delete state request * - * return sendRequest(request, request.getResponseType()); } + * @return the ResponseEntity */ + public Mono> deleteState(DeleteStateRequest request) { - public > ResponseEntity putState( - Consumer> putStateRequest) { - - final PutStateRequest.Builder builder = PutStateRequest.builder(); - - putStateRequest.accept(builder); - - return send(builder); - } - + Map queryParams = new HashMap<>(); + return this.webClient - public > ResponseEntity postState( - Consumer> postStateRequest) { + .delete() - final PostStateRequest.Builder builder = PostStateRequest.builder(); + .uri(u -> request.url(u, queryParams).build(queryParams)) - postStateRequest.accept(builder); + .retrieve() - return send(builder); + .toBodilessEntity(); } - - - public > ResponseEntity deleteState( - Consumer> deleteStateRequest) { + /** + * Deletes a single document specified by the given stateId activity, agent, and optional + * registration. + * + * The returned ResponseEntity contains the response headers. + * + * @param request The Consumer Builder for the delete state request + * + * @return the ResponseEntity + */ + public Mono> deleteState( + Consumer> request) { final DeleteStateRequest.Builder builder = DeleteStateRequest.builder(); - deleteStateRequest.accept(builder); + request.accept(builder); - return send(builder); + return deleteState(builder.build()); } + /** + * Deletes all documents specified by the given activityId, agent and optional registration. + * + * The returned ResponseEntity contains the response headers. + * + * @param request The parameters of the delete states request + * + * @return the ResponseEntity + */ + public Mono> deleteStates(DeleteStatesRequest request) { - public > ResponseEntity deleteStates( - Consumer> deleteStatesRequest) { - - final DeleteStatesRequest.Builder builder = DeleteStatesRequest.builder(); - - deleteStatesRequest.accept(builder); - - return send(builder); - - } - - - - public , B extends GetStateRequest.Builder, - T> ResponseEntity getState(Consumer> getStateRequest) { - - final GetStateRequest.Builder builder = GetStateRequest.builder(); - - getStateRequest.accept(builder); - - return send(builder); - - } - - public >, B extends GetStatesRequest.Builder, C, B>, - T> ResponseEntity getStates( - Consumer, ?, ?>> getStatesRequest) { - - final GetStatesRequest.Builder, ?, ?> builder = GetStatesRequest.builder(); - - getStatesRequest.accept(builder); - - return send(builder); - - } + Map queryParams = new HashMap<>(); + return this.webClient + .delete() - private , B extends Request.Builder, - T> ResponseEntity send(Request.Builder builder) { + .uri(u -> request.url(u, queryParams).build(queryParams)) - var request = builder.build(); + .retrieve() - return sendRequest(request, request.getResponseType()); + .toBodilessEntity(); } - /** - *

- * Convenient type-safe method for sending a {@link GetStateRequest} which expects an instance of - * a given JAVA class as a response. - *

- *

- * The {@link GetStateRequest} is the only xAPI request where the type of the response is not - * defined. Learning Record Providers can store ANY kind of data here. The type conversion of the - * returned state object happens based on the Content-Type header provided when - * the state was stored. If the stored state is incompatible with the - * Content-Type header or it cannot be converted to the expected response type - * then a {@link RuntimeException} is thrown. - *

- *

- * If the generic {@link XapiClient#send(XapiRequest)} method is used with {@link GetStateRequest} - * request then the state is returned as a String. - *

- * - * @param The response type is defined by the responseType parameter. - * @param request an {@link GetStateRequest} object. - * @param responseType a {@link Class} object defining the response type of the returning state. - * @return a {@link ResponseEntity} containing the response object . - * @see State - * Resources Description - * @throws RuntimeException when the returned state cannot be converted to the expected JAVA - * class. + * Deletes all documents specified by the given activityId, agent and optional registration. + * + * The returned ResponseEntity contains the response headers. + * + * @param request The Consumer Builder for the delete state request + * + * @return the ResponseEntity */ - public ResponseEntity send(GetStateRequest request, @NonNull Class responseType) { - return sendRequest(request, responseType); - } - - - public Mono
someRestCall(String name) { - return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class); - } - - private ResponseEntity sendRequest(Request request, @NonNull Class responseType) { - - - - // UriSpec uriSpec = client.method(request.getMethod()); + public Mono> deleteStates( + Consumer> deleteStatesRequest) { - // RequestBodySpec bodySpec = uriSpec.uri(uriBuilder -> request.url(uriBuilder).build()); - - // RequestHeadersSpec headersSpec = bodySpec.h - - // ResponseSpec responseSpec = headersSpec.header - - Map queryParams = new HashMap<>(); - - final RequestBodySpec r = webClient - - .method(request.getMethod()) - - .uri(uriBuilder -> request.url(uriBuilder, queryParams).build(queryParams)) - - .headers(headers -> new HttpHeaders()); - - final var body = request.getBody(); - - if (body != null) { - r.bodyValue(body); - } + final DeleteStatesRequest.Builder builder = DeleteStatesRequest.builder(); - return r.retrieve().toEntity(responseType) + deleteStatesRequest.accept(builder); - .onErrorResume(WebClientResponseException.class, ex -> { - if (ex.getStatusCode().value() == 404) { - return Mono.just(new ResponseEntity(HttpStatusCode.valueOf(404))); - } - log.warn("Unsuccessful request: ", ex); - log.debug(ex.getResponseBodyAsString()); - return Mono.error(ex); - }) + return deleteStates(builder.build()); - .block(); } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java new file mode 100644 index 00000000..48a6b7b4 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java @@ -0,0 +1,11 @@ + +package dev.learning.xapi.client; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TestApp { + + + +} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index 6c1b8cba..d5329b70 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -4,110 +4,227 @@ package dev.learning.xapi.client; - -import java.time.Instant; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import java.io.IOException; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.http.ResponseEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; /** - * DeleteStateRequest Tests. + * XapiClient Tests. * * @author Thomas Turrell-Croft */ -@DisplayName("DeleteStateRequest Tests") +@DisplayName("XapiClient Tests") +@SpringBootTest class XapiClientTests { + @Autowired + private WebClient.Builder webClientBuilder; + + private static MockWebServer mockWebServer; + private XapiClient client; + + @BeforeAll + static void setUp() throws IOException { + mockWebServer = new MockWebServer(); + mockWebServer.start(); + } + + @AfterAll + static void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @BeforeEach + void initialize() { + String baseUrl = String.format("http://localhost:%s", mockWebServer.getPort()); - XapiClient client = new XapiClient(null); + webClientBuilder.baseUrl(baseUrl); + client = new XapiClient(webClientBuilder); + + } @Test - void deleteState() { + void whenDeletingASingleStateThenMethodIsDelete() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); - ResponseEntity t = client.deleteState(r -> r.activityId("https://example.com/activity/1") + // When Deleting A Single State + client.deleteState(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark")); - + .stateId("bookmark")).block(); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + // Then Method Is Delete + assertThat(recordedRequest.getMethod(), is("DELETE")); } @Test - void deleteStates() { + void whenDeletingASingleStateThenPathIsExpected() throws InterruptedException { - client.deleteStates(r -> r.activityId("https://example.com/activity/1") + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Deleting A Single State + client.deleteState(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - ); + .stateId("bookmark")).block(); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } @Test - void putState() { + void whenDeletingASingleStateWithoutRegistrationThenMethodIsDelete() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); - client.putState(r -> r.activityId("https://example.com/activity/1") + // When Deleting A Single State Without Registration + client.deleteState(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + .stateId("bookmark")).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); - .stateId("bookmark") + // Then Method Is Delete + assertThat(recordedRequest.getMethod(), is("DELETE")); + } + + @Test + void whenDeletingASingleStateWithoutRegistrationThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Deleting A Single State Without Registration + client.deleteState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .state("Hello") + .stateId("bookmark")).block(); - ); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } @Test - void postState() { + void whenDeletingMultipleStatesThenMethodIsDelete() throws InterruptedException { - client.putState(r -> r.activityId("https://example.com/activity/1") + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Deleting Multiple States + client.deleteStates(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark") + ).block(); - .state("Hello") - - ); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + // Then Method Is Delete + assertThat(recordedRequest.getMethod(), is("DELETE")); } @Test - void getState() { + void whenDeletingMultipleStatesThenPathIsExpected() throws InterruptedException { - client.getState(r -> r.activityId("https://example.com/activity/1") + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Deleting Multiple States + client.deleteStates(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark")); + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6")); } @Test - void getStates() { + void whenDeletingMultipleStatesWithoutRegistrationThenMethodIsDelete() + throws InterruptedException { - client.getStates(r -> r.activityId("https://example.com/activity/1") + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Deleting Multiple States Without Registration + client.deleteStates(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Delete + assertThat(recordedRequest.getMethod(), is("DELETE")); + } + + @Test + void whenDeletingMultipleStatesWithoutRegistrationThenPathIsExpected() + throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Deleting Multiple States Without Registration + client.deleteStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D")); + } + + + // Test utility + private MultiValueMap getQueryParams(RecordedRequest recordedRequest) { - .since(Instant.parse("2023-01-30T22:27:09Z")) + UriComponents uriComponents = + UriComponentsBuilder.fromHttpUrl(recordedRequest.getRequestUrl().toString()).build(); - ); + return uriComponents.getQueryParams(); } diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/Score.java b/xapi-model/src/main/java/dev/learning/xapi/model/Score.java index ee79cce7..7edade36 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/Score.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/Score.java @@ -29,7 +29,7 @@ public class Score { */ @DecimalMax(value = "1.0") @DecimalMin(value = "-1.0") - private float scaled; + private Float scaled; /** * The score achieved by the Actor in the experience described by the Statement. From fac73378f2ca3ed79627f230233431d8c408cd6b Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 3 Feb 2023 17:19:54 +0000 Subject: [PATCH 42/74] added get but messy --- .../xapi/client/DeleteStateRequest.java | 2 +- .../xapi/client/DeleteStatesRequest.java | 2 +- .../learning/xapi/client/GetStateRequest.java | 10 ++- .../xapi/client/GetStatesRequest.java | 3 +- .../xapi/client/PostStateRequest.java | 10 +-- .../learning/xapi/client/PutStateRequest.java | 8 +- .../dev/learning/xapi/client/Request.java | 2 +- .../learning/xapi/client/StateRequest.java | 2 +- .../learning/xapi/client/StatesRequest.java | 9 +- .../dev/learning/xapi/client/XapiClient.java | 53 +++++++++++ .../learning/xapi/client/XapiClientTests.java | 88 ++++++++++++++++--- 11 files changed, 150 insertions(+), 39 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index 73d77289..1bd0da6d 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -12,7 +12,7 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -public class DeleteStateRequest extends StateRequest { +public class DeleteStateRequest extends StateRequest { @Override protected HttpMethod getMethod() { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index a2b3652c..2e7a885b 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -12,7 +12,7 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -public class DeleteStatesRequest extends StatesRequest { +public class DeleteStatesRequest extends StatesRequest { @Override protected HttpMethod getMethod() { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index 7c399b14..29f91595 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -1,5 +1,7 @@ package dev.learning.xapi.client; +import io.micrometer.common.lang.NonNull; +import lombok.Getter; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; @@ -11,13 +13,19 @@ * State Document GET * @author István Rátkai (Selindek) * @param + * @param */ @SuperBuilder -public class GetStateRequest extends StateRequest { +@Getter +public class GetStateRequest extends StateRequest { + + @NonNull + private final Class type; @Override protected HttpMethod getMethod() { return HttpMethod.GET; } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index 609ba888..ec2bc5ef 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -1,7 +1,6 @@ package dev.learning.xapi.client; import java.time.Instant; -import java.util.List; import java.util.Map; import java.util.Optional; import lombok.Getter; @@ -20,7 +19,7 @@ */ @SuperBuilder @Getter -public class GetStatesRequest extends StatesRequest> { +public class GetStatesRequest extends StatesRequest { private final Instant since; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index 9b6fec84..ee7f4810 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -16,7 +16,7 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -public class PostStateRequest extends StateRequest { +public class PostStateRequest extends StateRequest { /** * The state object to store. @@ -29,12 +29,4 @@ protected HttpMethod getMethod() { return HttpMethod.POST; } - @Override - protected Object getBody() { - - return state; - } - - - } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index b7fb03ae..124f6c1d 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -13,7 +13,7 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -public class PutStateRequest extends StateRequest { +public class PutStateRequest extends StateRequest { /** * The state object to store. @@ -26,10 +26,4 @@ protected HttpMethod getMethod() { return HttpMethod.PUT; } - @Override - protected Object getBody() { - - return state; - } - } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 38c3e141..b8883a73 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -16,7 +16,7 @@ @SuperBuilder @Getter @RequiredArgsConstructor -abstract class Request { +abstract class Request { protected abstract UriBuilder url(UriBuilder uriBuilder, Map queryParams); diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index 397160c5..3a91e2f0 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -14,7 +14,7 @@ */ @SuperBuilder @Getter -abstract class StateRequest extends StatesRequest { +abstract class StateRequest extends StatesRequest { /** * The stateId query parameter. diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 0a872a27..f4b247e5 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -24,7 +24,7 @@ */ @SuperBuilder @Getter -abstract class StatesRequest extends Request { +abstract class StatesRequest extends Request { private final ObjectMapper objectMapper = new ObjectMapper(); @@ -72,9 +72,12 @@ public String agentToJsonString() { } + // public abstract static class Builder> extends + // Actor.Builder { - public abstract static class Builder, - B extends StatesRequest.Builder> extends Request.Builder { + + public abstract static class Builder> + extends Request.Builder { /** * Consumer Builder for agent. diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 9bef01ad..8c9c0d23 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -38,6 +38,59 @@ public XapiClient(WebClient.Builder builder) { .build(); } + /** + * Gets a single document specified by the given stateId activity, agent, and optional + * registration. + * + * The returned ResponseEntity contains the response headers and body. + * + * @param + * + * @param the body type + * + * @param request The parameters of the get state request + * + * @return the ResponseEntity + */ + public Mono> getState(GetStateRequest request, Class body) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .get() + + .uri(u -> request.url(u, queryParams).build(queryParams)) + + .retrieve() + + .toEntity(body); + + } + + /** + * Gets a single document specified by the given stateId activity, agent, and optional + * registration. + * + * The returned ResponseEntity contains the response headers and body. + * + * @param request The Consumer Builder for the get state request + * + * @return the ResponseEntity + */ + public Mono> getState(Consumer> request, + Class body) { + + final GetStateRequest.Builder builder = GetStateRequest.builder(); + + request.accept(builder); + + return getState(builder.build(), body); + + } + + + /** * Deletes a single document specified by the given stateId activity, agent, and optional * registration. diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index d5329b70..fb9d45e7 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -6,17 +6,17 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; -import java.io.IOException; +import static org.hamcrest.core.IsInstanceOf.instanceOf; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.ResponseEntity; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriComponents; @@ -34,27 +34,89 @@ class XapiClientTests { @Autowired private WebClient.Builder webClientBuilder; - private static MockWebServer mockWebServer; + private MockWebServer mockWebServer; private XapiClient client; - @BeforeAll - static void setUp() throws IOException { + @BeforeEach + void setUp() throws Exception { mockWebServer = new MockWebServer(); mockWebServer.start(); + + String baseUrl = String.format("http://localhost:%s", mockWebServer.getPort()); + + webClientBuilder.baseUrl(baseUrl); + client = new XapiClient(webClientBuilder); + } - @AfterAll - static void tearDown() throws IOException { + @AfterEach + void tearDown() throws Exception { mockWebServer.shutdown(); } - @BeforeEach - void initialize() { - String baseUrl = String.format("http://localhost:%s", mockWebServer.getPort()); + @Test + void whenGettingASingleStateThenMethodIsGet() throws InterruptedException { - webClientBuilder.baseUrl(baseUrl); - client = new XapiClient(webClientBuilder); + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting A Single State + client.getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark"), String.class).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Get + assertThat(recordedRequest.getMethod(), is("GET")); + } + + @Test + void whenGettingASingleStateThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + // When Getting A Single State + client.getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark"), String.class).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); + } + + + + @Test + void test() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("Hello World!").addHeader("Content-Type", "text/plain; charset=utf-8")); + + // When Getting A Single State + ResponseEntity response = client + .getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark"), String.class) + + .block(); + + // Then Path Is Expected + assertThat(response.getBody(), instanceOf(String.class)); } @Test From 0d47d8cf0bd1736e5d8b42de0f3f8c59fcb71353 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 3 Feb 2023 17:58:03 +0000 Subject: [PATCH 43/74] stuff --- .../dev/learning/xapi/client/GetStateRequest.java | 3 +-- .../java/dev/learning/xapi/client/XapiClient.java | 14 ++++++-------- .../dev/learning/xapi/client/XapiClientTests.java | 8 +++++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index 29f91595..83b6cd1e 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -13,14 +13,13 @@ * State Document GET * @author István Rátkai (Selindek) * @param - * @param */ @SuperBuilder @Getter public class GetStateRequest extends StateRequest { @NonNull - private final Class type; + private final Class type; @Override protected HttpMethod getMethod() { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 8c9c0d23..00d34089 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -46,13 +46,13 @@ public XapiClient(WebClient.Builder builder) { * * @param * - * @param the body type - * + * @param + * * @param request The parameters of the get state request * * @return the ResponseEntity */ - public Mono> getState(GetStateRequest request, Class body) { + public Mono> getState(GetStateRequest request) { Map queryParams = new HashMap<>(); @@ -64,7 +64,7 @@ public Mono> getState(GetStateRequest request, Class .retrieve() - .toEntity(body); + .toEntity(request.getType()); } @@ -78,19 +78,17 @@ public Mono> getState(GetStateRequest request, Class * * @return the ResponseEntity */ - public Mono> getState(Consumer> request, - Class body) { + public Mono> getState(Consumer> request) { final GetStateRequest.Builder builder = GetStateRequest.builder(); request.accept(builder); - return getState(builder.build(), body); + return getState(builder.build()); } - /** * Deletes a single document specified by the given stateId activity, agent, and optional * registration. diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index fb9d45e7..db9a57ed 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -66,7 +66,7 @@ void whenGettingASingleStateThenMethodIsGet() throws InterruptedException { .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark"), String.class).block(); + .stateId("bookmark")).block(); RecordedRequest recordedRequest = mockWebServer.takeRequest(); @@ -86,7 +86,7 @@ void whenGettingASingleStateThenPathIsExpected() throws InterruptedException { .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark"), String.class).block(); + .stateId("bookmark")).block(); RecordedRequest recordedRequest = mockWebServer.takeRequest(); @@ -111,7 +111,9 @@ void test() throws InterruptedException { .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark"), String.class) + .stateId("bookmark") + + .type(String.class)) .block(); From d6e5e5d1316a1b1c981066f9a2a1f1a55127c913 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 6 Feb 2023 18:35:55 +0000 Subject: [PATCH 44/74] reasonable state --- .../learning/xapi/client/GetStateRequest.java | 6 +- .../xapi/client/GetStatesRequest.java | 2 +- .../xapi/client/PostStateRequest.java | 7 + .../learning/xapi/client/PutStateRequest.java | 7 + .../learning/xapi/client/StatesRequest.java | 6 +- .../dev/learning/xapi/client/XapiClient.java | 149 ++++- .../xapi/client/DeleteStatesRequestTests.java | 35 ++ .../xapi/client/GetStateRequestTests.java | 2 +- .../learning/xapi/client/XapiClientTests.java | 516 +++++++++++++++++- 9 files changed, 700 insertions(+), 30 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index 83b6cd1e..c8553872 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -1,6 +1,5 @@ package dev.learning.xapi.client; -import io.micrometer.common.lang.NonNull; import lombok.Getter; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; @@ -16,10 +15,7 @@ */ @SuperBuilder @Getter -public class GetStateRequest extends StateRequest { - - @NonNull - private final Class type; +public class GetStateRequest extends StateRequest { @Override protected HttpMethod getMethod() { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index ec2bc5ef..f67d9c98 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -19,7 +19,7 @@ */ @SuperBuilder @Getter -public class GetStatesRequest extends StatesRequest { +public class GetStatesRequest extends StatesRequest { private final Instant since; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index ee7f4810..415ed912 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -1,8 +1,11 @@ package dev.learning.xapi.client; +import lombok.Builder.Default; +import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; /** * Request for posting a single State document. @@ -16,8 +19,12 @@ * @author István Rátkai (Selindek) */ @SuperBuilder +@Getter public class PostStateRequest extends StateRequest { + @Default + private MediaType contentType = MediaType.APPLICATION_JSON; + /** * The state object to store. */ diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index 124f6c1d..b85e3cc8 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -1,8 +1,11 @@ package dev.learning.xapi.client; +import lombok.Builder.Default; +import lombok.Getter; import lombok.NonNull; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; /** * Request for putting a single State document. @@ -13,8 +16,12 @@ * @author István Rátkai (Selindek) */ @SuperBuilder +@Getter public class PutStateRequest extends StateRequest { + @Default + private MediaType contentType = MediaType.APPLICATION_JSON; + /** * The state object to store. */ diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index f4b247e5..06a92f4d 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -61,7 +61,7 @@ protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) } - public String agentToJsonString() { + private String agentToJsonString() { try { return objectMapper.writeValueAsString(agent); @@ -72,10 +72,6 @@ public String agentToJsonString() { } - // public abstract static class Builder> extends - // Actor.Builder { - - public abstract static class Builder> extends Request.Builder { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 00d34089..09d92863 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -52,19 +52,19 @@ public XapiClient(WebClient.Builder builder) { * * @return the ResponseEntity */ - public Mono> getState(GetStateRequest request) { + public Mono> getState(GetStateRequest request, Class bodyType) { Map queryParams = new HashMap<>(); return this.webClient - .get() + .method(request.getMethod()) .uri(u -> request.url(u, queryParams).build(queryParams)) .retrieve() - .toEntity(request.getType()); + .toEntity(bodyType); } @@ -78,16 +78,147 @@ public Mono> getState(GetStateRequest request) { * * @return the ResponseEntity */ - public Mono> getState(Consumer> request) { + public Mono> getState(Consumer> request, + Class bodyType) { - final GetStateRequest.Builder builder = GetStateRequest.builder(); + final GetStateRequest.Builder builder = GetStateRequest.builder(); request.accept(builder); - return getState(builder.build()); + return getState(builder.build(), bodyType); } + public Mono> getStates(GetStatesRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) + + .retrieve() + + .toEntity(String[].class); + + } + + public Mono> getStates( + Consumer> request) { + + final GetStatesRequest.Builder builder = GetStatesRequest.builder(); + + request.accept(builder); + + return getStates(builder.build()); + + } + + /** + * Posts a single document specified by the given stateId activity, agent, and optional + * registration. + * + * The returned ResponseEntity contains the response headers and body. + * + * @param request The parameters of the post state request + * + * @return the ResponseEntity + */ + public Mono> postState(PostStateRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) + + .contentType(request.getContentType()) + + .bodyValue(request.getState()) + + .retrieve() + + .toBodilessEntity(); + + } + + /** + * Gets a single document specified by the given stateId activity, agent, and optional + * registration. + * + * The returned ResponseEntity contains the response headers and body. + * + * @param request The Consumer Builder for the get state request + * + * @return the ResponseEntity + */ + public Mono> postState(Consumer> request) { + + final PostStateRequest.Builder builder = PostStateRequest.builder(); + + request.accept(builder); + + return postState(builder.build()); + + } + + /** + * Gets a single document specified by the given stateId activity, agent, and optional + * registration. + * + * The returned ResponseEntity contains the response headers and body. + * + * @param + * + * @param + * + * @param request The parameters of the get state request + * + * @return the ResponseEntity + */ + public Mono> putState(PutStateRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) + + .contentType(request.getContentType()) + + .bodyValue(request.getState()) + + .retrieve() + + .toBodilessEntity(); + + } + + /** + * Gets a single document specified by the given stateId activity, agent, and optional + * registration. + * + * The returned ResponseEntity contains the response headers and body. + * + * @param request The Consumer Builder for the get state request + * + * @return the ResponseEntity + */ + public Mono> putState(Consumer> request) { + + final PutStateRequest.Builder builder = PutStateRequest.builder(); + + request.accept(builder); + + return putState(builder.build()); + + } /** * Deletes a single document specified by the given stateId activity, agent, and optional @@ -105,7 +236,7 @@ public Mono> deleteState(DeleteStateRequest request) { return this.webClient - .delete() + .method(request.getMethod()) .uri(u -> request.url(u, queryParams).build(queryParams)) @@ -151,7 +282,7 @@ public Mono> deleteStates(DeleteStatesRequest request) { return this.webClient - .delete() + .method(request.getMethod()) .uri(u -> request.url(u, queryParams).build(queryParams)) @@ -181,6 +312,4 @@ public Mono> deleteStates( } - - } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java index 5af50b35..4a48a2fa 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java @@ -11,6 +11,7 @@ import java.net.URI; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.web.util.UriBuilder; @@ -41,6 +42,40 @@ void whenBuildingDeleteStatesRequestWithAllParametersThenNoExceptionIsThrown() { } + @Test + void whenBuildingDeleteStatesRequestWithRegistrationAsUUIDTypeThenNoExceptionIsThrown() { + + // When Building Delete States Request With Registration As UUID Type + Builder builder = DeleteStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration(UUID.fromString("67828e3a-d116-4e18-8af3-2d2c59e27be6")); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + + @Test + void whenBuildingDeleteStatesRequestWithActivityIdAsURITypeThenNoExceptionIsThrown() { + + // When Building Delete States Request With ActivityId As URI Type + Builder builder = DeleteStatesRequest.builder() + + .activityId(URI.create("https://example.com/activity/1")) + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration(("67828e3a-d116-4e18-8af3-2d2c59e27be6")); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + @Test void whenBuildingDeleteStatesRequestWithoutRegistrationThenNoExceptionIsThrown() { diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java index 5000f9a3..939e78e3 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java @@ -21,7 +21,7 @@ class GetStateRequestTests { void whenBuildingGetStateRequestWithAllParametersThenNoExceptionIsThrown() { // When Building GetStateRequest With All Parameters - Builder builder = GetStateRequest.builder() + Builder builder = GetStateRequest.builder() .activityId("https://example.com/activity/1") diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index db9a57ed..a7daed53 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.client.WebClient; @@ -54,6 +55,8 @@ void tearDown() throws Exception { mockWebServer.shutdown(); } + // Get Single State + @Test void whenGettingASingleStateThenMethodIsGet() throws InterruptedException { @@ -66,7 +69,7 @@ void whenGettingASingleStateThenMethodIsGet() throws InterruptedException { .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark")).block(); + .stateId("bookmark"), String.class).block(); RecordedRequest recordedRequest = mockWebServer.takeRequest(); @@ -86,7 +89,7 @@ void whenGettingASingleStateThenPathIsExpected() throws InterruptedException { .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark")).block(); + .stateId("bookmark"), String.class).block(); RecordedRequest recordedRequest = mockWebServer.takeRequest(); @@ -95,15 +98,56 @@ void whenGettingASingleStateThenPathIsExpected() throws InterruptedException { "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } + @Test + void whenGettingASingleStateWithoutRegistrationThenMethodIsGet() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Getting A Single State Without Registration + client.getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark"), String.class) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Get + assertThat(recordedRequest.getMethod(), is("GET")); + } + + @Test + void whenGettingASingleStateWithoutRegistrationThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Getting A Single State Without Registration + client.getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark"), String.class) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); + } @Test - void test() throws InterruptedException { + void givenStateContentTypeIsTextPlainWhenGettingStateThenBodyIsInstanceOfString() + throws InterruptedException { + // Given State Content Type Is Text Plain mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") .setBody("Hello World!").addHeader("Content-Type", "text/plain; charset=utf-8")); - // When Getting A Single State + // When Getting State ResponseEntity response = client .getState(r -> r.activityId("https://example.com/activity/1") @@ -111,16 +155,336 @@ void test() throws InterruptedException { .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .stateId("bookmark") + .stateId("bookmark"), String.class) + + .block(); - .type(String.class)) + // Then Body Is Instance Of String + assertThat(response.getBody(), instanceOf(String.class)); + } + + @Test + void givenStateContentTypeIsTextPlainWhenGettingStateThenBodyIsExpected() + throws InterruptedException { + + // Given State Content Type Is Text Plain + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("Hello World!").addHeader("Content-Type", "text/plain; charset=utf-8")); + + // When Getting State + ResponseEntity response = client + .getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark"), String.class) .block(); + // Then Body Is Expected + assertThat(response.getBody(), is("Hello World!")); + } + + // Post Single State + + @Test + void whenPostingASingleStateThenMethodIsPost() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Posting A Single State + client.postState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Post + assertThat(recordedRequest.getMethod(), is("POST")); + } + + @Test + void whenPostingASingleStateThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Posting A Single State + client.postState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + // Then Path Is Expected - assertThat(response.getBody(), instanceOf(String.class)); + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); + } + + @Test + void whenPostingASingleStateWithContentTypeTextPlainThenContentTypeHeaderIsTextPlain() + throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Posting A Single State With Content Type Text Plain + client.postState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!") + + .contentType(MediaType.TEXT_PLAIN)) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Content Type Header Is Text Plain + assertThat(recordedRequest.getHeader("content-type"), is("text/plain")); + } + + @Test + void whenPostingASingleStateWithoutContentTypeThenContentTypeHeaderIsApplicationJson() + throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Posting A Single State Without Content Type + client.postState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Content Type Header Is Application Json + assertThat(recordedRequest.getHeader("content-type"), is("application/json")); + } + + @Test + void whenPostingASingleStateWithoutRegistrationThenMethodIsPost() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Posting A Single State Without Registration + client.postState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Post + assertThat(recordedRequest.getMethod(), is("POST")); + } + + @Test + void whenPostingASingleStateWithoutRegistrationThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Posting A Single State Without Registration + client.postState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); + } + + // Put Single State + + @Test + void whenPuttingASingleStateThenMethodIsPut() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Putting A Single State + client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Post + assertThat(recordedRequest.getMethod(), is("PUT")); + } + + @Test + void whenPuttingASingleStateThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Putting A Single State + client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); + } + + @Test + void whenPuttingASingleStateWithContentTypeTextPlainThenContentTypeHeaderIsTextPlain() + throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Putting A Single State With Content Type Text Plain + client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!") + + .contentType(MediaType.TEXT_PLAIN)) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Content Type Header Is Text Plain + assertThat(recordedRequest.getHeader("content-type"), is("text/plain")); } + @Test + void whenPuttingASingleStateWithoutContentTypeThenContentTypeHeaderIsApplicationJson() + throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Putting A Single State Without Content Type + client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Content Type Header Is Application Json + assertThat(recordedRequest.getHeader("content-type"), is("application/json")); + } + + @Test + void whenPuttingASingleStateWithoutRegistrationThenMethodIsPut() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Putting A Single State Without Registration + client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Post + assertThat(recordedRequest.getMethod(), is("PUT")); + } + + @Test + void whenPuttingASingleStateWithoutRegistrationThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 No Content")); + + // When Putting A Single State Without Registration + client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); + } + + // Deleting Single State + @Test void whenDeletingASingleStateThenMethodIsDelete() throws InterruptedException { @@ -201,6 +565,143 @@ void whenDeletingASingleStateWithoutRegistrationThenPathIsExpected() throws Inte "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } + // Getting Multiple States + + @Test + void whenGettingMultipleStatesThenMethodIsGet() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"State1\", \"State2\", \"State3\"]") + .addHeader("Content-Type", "application/json; charset=utf-8")); + + // When Getting Multiple States + client.getStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Get + assertThat(recordedRequest.getMethod(), is("GET")); + } + + @Test + void whenGettingMultipleStatesThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"State1\", \"State2\", \"State3\"]") + .addHeader("Content-Type", "application/json; charset=utf-8")); + + // When Getting Multiple States + client.getStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6")) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6")); + } + + @Test + void whenGettingMultipleStatesWithoutRegistrationThenMethodIsGet() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"State1\", \"State2\", \"State3\"]") + .addHeader("Content-Type", "application/json; charset=utf-8")); + + // When Getting Multiple States Without Registration + client.getStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com"))) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Get + assertThat(recordedRequest.getMethod(), is("GET")); + } + + @Test + void whenGettingMultipleStatesWithoutRegistrationThenPathIsExpected() + throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"State1\", \"State2\", \"State3\"]") + .addHeader("Content-Type", "application/json; charset=utf-8")); + + // When Getting Multiple States Without Registration + client.getStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com"))) + + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D")); + } + + @Test + void givenMultipleStatesExistWhenGettingMultipleStatesThenBodyIsInstanceOfStringArray() + throws InterruptedException { + + // Given Multiple States Exist + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"State1\", \"State2\", \"State3\"]") + .addHeader("Content-Type", "application/json; charset=utf-8")); + + // When Getting Multiple States + ResponseEntity response = client + .getStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6")) + + .block(); + + // Then Body Is Instance Of String Array + assertThat(response.getBody(), instanceOf(String[].class)); + } + + @Test + void givenMultipleStatesExistWhenGettingMultipleStatesThenBodyIsExpected() + throws InterruptedException { + + // Given Multiple States Exist + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"State1\", \"State2\", \"State3\"]") + .addHeader("Content-Type", "application/json; charset=utf-8")); + + // When Getting Multiple States + ResponseEntity response = client + .getStates(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6")) + + .block(); + + // Then Body Is Expected + assertThat(response.getBody(), is(new String[] {"State1", "State2", "State3"})); + } + + // Deleting Multiple States + @Test void whenDeletingMultipleStatesThenMethodIsDelete() throws InterruptedException { @@ -281,7 +782,6 @@ void whenDeletingMultipleStatesWithoutRegistrationThenPathIsExpected() "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D")); } - // Test utility private MultiValueMap getQueryParams(RecordedRequest recordedRequest) { From 4d20918f534fd6d3253f40451cd28185cf636fe7 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 6 Feb 2023 18:36:21 +0000 Subject: [PATCH 45/74] tidy --- .../dev/learning/xapi/client/XapiClientTests.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index a7daed53..5f0feecc 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -18,10 +18,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; /** * XapiClient Tests. @@ -782,16 +779,6 @@ void whenDeletingMultipleStatesWithoutRegistrationThenPathIsExpected() "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D")); } - // Test utility - private MultiValueMap getQueryParams(RecordedRequest recordedRequest) { - - UriComponents uriComponents = - UriComponentsBuilder.fromHttpUrl(recordedRequest.getRequestUrl().toString()).build(); - - return uriComponents.getQueryParams(); - - } - } From a86d136e510fc8fcc5ecd16143bf57400efb143a Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 7 Feb 2023 16:58:38 +0000 Subject: [PATCH 46/74] wip --- .../dev/learning/xapi/client/XapiClient.java | 98 ++++++++++--------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 09d92863..3b6e80dc 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -1,7 +1,5 @@ package dev.learning.xapi.client; -import com.fasterxml.jackson.databind.ObjectMapper; -import dev.learning.xapi.model.Actor; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -27,8 +25,6 @@ public class XapiClient { * * @param builder a {@link WebClient.Builder} object. The caller must set the baseUrl and the * authorization header. - * @param objectMapper an {@link ObjectMapper}. It is used for converting {@link Actor} query - * parameters to JSON string during xAPI requests. */ public XapiClient(WebClient.Builder builder) { this.webClient = builder @@ -44,10 +40,6 @@ public XapiClient(WebClient.Builder builder) { * * The returned ResponseEntity contains the response headers and body. * - * @param - * - * @param - * * @param request The parameters of the get state request * * @return the ResponseEntity @@ -89,33 +81,6 @@ public Mono> getState(Consumer Mono> getStates(GetStatesRequest request) { - - Map queryParams = new HashMap<>(); - - return this.webClient - - .method(request.getMethod()) - - .uri(u -> request.url(u, queryParams).build(queryParams)) - - .retrieve() - - .toEntity(String[].class); - - } - - public Mono> getStates( - Consumer> request) { - - final GetStatesRequest.Builder builder = GetStatesRequest.builder(); - - request.accept(builder); - - return getStates(builder.build()); - - } - /** * Posts a single document specified by the given stateId activity, agent, and optional * registration. @@ -147,12 +112,12 @@ public Mono> postState(PostStateRequest request) { } /** - * Gets a single document specified by the given stateId activity, agent, and optional + * Posts a single document specified by the given stateId activity, agent, and optional * registration. * * The returned ResponseEntity contains the response headers and body. * - * @param request The Consumer Builder for the get state request + * @param request The Consumer Builder for the post state request * * @return the ResponseEntity */ @@ -167,16 +132,12 @@ public Mono> postState(Consumer - * - * @param - * - * @param request The parameters of the get state request + * @param request The parameters of the put state request * * @return the ResponseEntity */ @@ -201,12 +162,12 @@ public Mono> putState(PutStateRequest request) { } /** - * Gets a single document specified by the given stateId activity, agent, and optional + * Puts a single document specified by the given stateId activity, agent, and optional * registration. * * The returned ResponseEntity contains the response headers and body. * - * @param request The Consumer Builder for the get state request + * @param request The Consumer Builder for the put state request * * @return the ResponseEntity */ @@ -267,6 +228,51 @@ public Mono> deleteState( } + /** + * Gets all stateId's specified by the given activityId, agent and optional registration and since + * parameters. + * + * @param request The parameters of the get states request + * + * @return the ResponseEntity + */ + public Mono> getStates(GetStatesRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) + + .retrieve() + + .toEntity(String[].class); + + } + + /** + * Gets all stateId's specified by the given activityId, agent and optional registration and since + * parameters. + * + * The returned ResponseEntity contains the response headers. + * + * @param request The Consumer Builder for the get states request + * + * @return the ResponseEntity + */ + public Mono> getStates( + Consumer> request) { + + final GetStatesRequest.Builder builder = GetStatesRequest.builder(); + + request.accept(builder); + + return getStates(builder.build()); + + } + /** * Deletes all documents specified by the given activityId, agent and optional registration. * @@ -297,7 +303,7 @@ public Mono> deleteStates(DeleteStatesRequest request) { * * The returned ResponseEntity contains the response headers. * - * @param request The Consumer Builder for the delete state request + * @param request The Consumer Builder for the delete states request * * @return the ResponseEntity */ From 54409e0992d6b9fcb4bb4050e6d8e8747d915f8a Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 7 Feb 2023 17:38:19 +0000 Subject: [PATCH 47/74] Tip --- .../learning/xapi/client/GetStateRequest.java | 2 +- .../xapi/client/GetStatesRequest.java | 5 +- .../dev/learning/xapi/client/XapiClient.java | 70 ++++++++++++------- 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index c8553872..8f744f94 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -10,8 +10,8 @@ * @see Single * State Document GET + * * @author István Rátkai (Selindek) - * @param */ @SuperBuilder @Getter diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index f67d9c98..f3cf4206 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -14,13 +14,16 @@ * @see Multiple * State Document GET + * * @author István Rátkai (Selindek) - * @param */ @SuperBuilder @Getter public class GetStatesRequest extends StatesRequest { + /** + * Only ids of states stored since the specified instant (exclusive) are returned. + */ private final Instant since; @Override diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 3b6e80dc..eb634481 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -38,10 +38,12 @@ public XapiClient(WebClient.Builder builder) { * Gets a single document specified by the given stateId activity, agent, and optional * registration. * + *

* The returned ResponseEntity contains the response headers and body. - * + *

+ * * @param request The parameters of the get state request - * + * * @return the ResponseEntity */ public Mono> getState(GetStateRequest request, Class bodyType) { @@ -64,8 +66,10 @@ public Mono> getState(GetStateRequest request, Class bo * Gets a single document specified by the given stateId activity, agent, and optional * registration. * + *

* The returned ResponseEntity contains the response headers and body. - * + *

+ * * @param request The Consumer Builder for the get state request * * @return the ResponseEntity @@ -85,10 +89,12 @@ public Mono> getState(Consumer * The returned ResponseEntity contains the response headers and body. - * + *

+ * * @param request The parameters of the post state request - * + * * @return the ResponseEntity */ public Mono> postState(PostStateRequest request) { @@ -115,8 +121,10 @@ public Mono> postState(PostStateRequest request) { * Posts a single document specified by the given stateId activity, agent, and optional * registration. * + *

* The returned ResponseEntity contains the response headers and body. - * + *

+ * * @param request The Consumer Builder for the post state request * * @return the ResponseEntity @@ -135,10 +143,12 @@ public Mono> postState(Consumer * The returned ResponseEntity contains the response headers and body. - * + *

+ * * @param request The parameters of the put state request - * + * * @return the ResponseEntity */ public Mono> putState(PutStateRequest request) { @@ -165,8 +175,10 @@ public Mono> putState(PutStateRequest request) { * Puts a single document specified by the given stateId activity, agent, and optional * registration. * + *

* The returned ResponseEntity contains the response headers and body. - * + *

+ * * @param request The Consumer Builder for the put state request * * @return the ResponseEntity @@ -185,10 +197,12 @@ public Mono> putState(Consumer * The returned ResponseEntity contains the response headers. + *

* * @param request The parameters of the delete state request - * + * * @return the ResponseEntity */ public Mono> deleteState(DeleteStateRequest request) { @@ -211,8 +225,10 @@ public Mono> deleteState(DeleteStateRequest request) { * Deletes a single document specified by the given stateId activity, agent, and optional * registration. * + *

* The returned ResponseEntity contains the response headers. - * + *

+ * * @param request The Consumer Builder for the delete state request * * @return the ResponseEntity @@ -231,9 +247,9 @@ public Mono> deleteState( /** * Gets all stateId's specified by the given activityId, agent and optional registration and since * parameters. - * + * * @param request The parameters of the get states request - * + * * @return the ResponseEntity */ public Mono> getStates(GetStatesRequest request) { @@ -255,11 +271,13 @@ public Mono> getStates(GetStatesRequest request) { /** * Gets all stateId's specified by the given activityId, agent and optional registration and since * parameters. - * + * + *

* The returned ResponseEntity contains the response headers. - * + *

+ * * @param request The Consumer Builder for the get states request - * + * * @return the ResponseEntity */ public Mono> getStates( @@ -275,11 +293,13 @@ public Mono> getStates( /** * Deletes all documents specified by the given activityId, agent and optional registration. - * + * + *

* The returned ResponseEntity contains the response headers. - * + *

+ * * @param request The parameters of the delete states request - * + * * @return the ResponseEntity */ public Mono> deleteStates(DeleteStatesRequest request) { @@ -300,19 +320,21 @@ public Mono> deleteStates(DeleteStatesRequest request) { /** * Deletes all documents specified by the given activityId, agent and optional registration. - * + * + *

* The returned ResponseEntity contains the response headers. - * + *

+ * * @param request The Consumer Builder for the delete states request - * + * * @return the ResponseEntity */ public Mono> deleteStates( - Consumer> deleteStatesRequest) { + Consumer> request) { final DeleteStatesRequest.Builder builder = DeleteStatesRequest.builder(); - deleteStatesRequest.accept(builder); + request.accept(builder); return deleteStates(builder.build()); From 084b73b1d28a9ec3fa032c9a8c61f5d45fb891ba Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 7 Feb 2023 18:42:04 +0000 Subject: [PATCH 48/74] fix --- xapi-client/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/pom.xml b/xapi-client/pom.xml index cb7e5f23..e039396d 100644 --- a/xapi-client/pom.xml +++ b/xapi-client/pom.xml @@ -4,7 +4,7 @@ dev.learning.xapi xapi-build - 1.0.1-SNAPSHOT + 1.0.3-SNAPSHOT xapi-client xAPI Client From bf9b0fce037ae9131479fb460e59e9aeafbbf8a8 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Wed, 8 Feb 2023 14:27:21 +0000 Subject: [PATCH 49/74] tip --- xapi-client/pom.xml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/xapi-client/pom.xml b/xapi-client/pom.xml index e039396d..c551b3db 100644 --- a/xapi-client/pom.xml +++ b/xapi-client/pom.xml @@ -6,9 +6,12 @@ xapi-build 1.0.3-SNAPSHOT + xapi-client + xAPI Client learning.dev xAPI Client + org.springframework.boot @@ -39,16 +42,13 @@ test - org.apache.commons - commons-lang3 + io.netty + netty-resolver-dns-native-macos + osx-aarch_64 test - - io.netty - netty-resolver-dns-native-macos - osx-aarch_64 - + @@ -57,4 +57,5 @@ + From 6a745c8c8cb4ebf6270ba4caed349474b6646625 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Wed, 8 Feb 2023 14:38:07 +0000 Subject: [PATCH 50/74] tip --- .../main/java/dev/learning/xapi/client/GetStateRequest.java | 3 --- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index 8f744f94..928b150f 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -1,6 +1,5 @@ package dev.learning.xapi.client; -import lombok.Getter; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; @@ -14,7 +13,6 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -@Getter public class GetStateRequest extends StateRequest { @Override @@ -22,5 +20,4 @@ protected HttpMethod getMethod() { return HttpMethod.GET; } - } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index eb634481..5d0b32b5 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -11,6 +11,7 @@ * Client for communicating with LRS or service which implements some of the xAPI communication * resources. * + * @author Thomas Turrell-Croft * @author István Rátkai (Selindek) * @see xAPI From 28684268e5283546ecbb3544a6270978ac180a6e Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Wed, 8 Feb 2023 14:43:47 +0000 Subject: [PATCH 51/74] tip --- .../main/java/dev/learning/xapi/client/DeleteStateRequest.java | 1 + .../main/java/dev/learning/xapi/client/DeleteStatesRequest.java | 1 + .../main/java/dev/learning/xapi/client/PostStateRequest.java | 1 + .../src/main/java/dev/learning/xapi/client/PutStateRequest.java | 1 + xapi-client/src/main/java/dev/learning/xapi/client/Request.java | 2 -- .../src/main/java/dev/learning/xapi/client/StateRequest.java | 1 - .../src/main/java/dev/learning/xapi/client/StatesRequest.java | 2 +- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 1 + 8 files changed, 6 insertions(+), 4 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index 1bd0da6d..07dc6f61 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -9,6 +9,7 @@ * @see Single * State Document DELETE + * * @author István Rátkai (Selindek) */ @SuperBuilder diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index 2e7a885b..f0d502f4 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -9,6 +9,7 @@ * @see Multiple * State Document DELETE + * * @author István Rátkai (Selindek) */ @SuperBuilder diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index 415ed912..d52cda6f 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -16,6 +16,7 @@ * @see JSON * Procedure with Requirements + * * @author István Rátkai (Selindek) */ @SuperBuilder diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index b85e3cc8..c0914644 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -13,6 +13,7 @@ * @see Single * State Document PUT + * * @author István Rátkai (Selindek) */ @SuperBuilder diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index b8883a73..5b49fcf9 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -11,7 +11,6 @@ * Base class for xAPI request. * * @author István Rátkai (Selindek) - * @param The type of the response body. Can be {@link Void} for responses without body. */ @SuperBuilder @Getter @@ -27,5 +26,4 @@ abstract class Request { */ protected abstract HttpMethod getMethod(); - } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index 3a91e2f0..b9180816 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -10,7 +10,6 @@ * Abstract superclass for state requests manipulating a single state document. * * @author István Rátkai (Selindek) - * @param The response type of the request */ @SuperBuilder @Getter diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 06a92f4d..b3bc4fda 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -19,8 +19,8 @@ * @see State * Resource + * * @author István Rátkai (Selindek) - * @param The response type of the request */ @SuperBuilder @Getter diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 5d0b32b5..f8ff2271 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -13,6 +13,7 @@ * * @author Thomas Turrell-Croft * @author István Rátkai (Selindek) + * * @see xAPI * communication resources From 20aea425be8e02980b02cbc52ee0e78d10b35526 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Wed, 8 Feb 2023 16:04:18 +0000 Subject: [PATCH 52/74] tip --- xapi-client/src/main/java/dev/learning/xapi/client/Request.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 5b49fcf9..a33726ce 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -1,7 +1,6 @@ package dev.learning.xapi.client; import java.util.Map; -import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; @@ -13,7 +12,6 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -@Getter @RequiredArgsConstructor abstract class Request { From 69a3260d44e3d65d5c12304371be0cbbc0707886 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Wed, 8 Feb 2023 16:11:28 +0000 Subject: [PATCH 53/74] tip --- xapi-client/src/main/java/dev/learning/xapi/client/Request.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index a33726ce..043d48db 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -1,7 +1,6 @@ package dev.learning.xapi.client; import java.util.Map; -import lombok.RequiredArgsConstructor; import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; import org.springframework.web.util.UriBuilder; @@ -12,7 +11,6 @@ * @author István Rátkai (Selindek) */ @SuperBuilder -@RequiredArgsConstructor abstract class Request { protected abstract UriBuilder url(UriBuilder uriBuilder, Map queryParams); From 65b239bbe6c79ee652576de6f185244641e583d2 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 12:54:52 +0000 Subject: [PATCH 54/74] Tip --- .../xapi/client/DeleteStateRequestTests.java | 2 +- .../xapi/client/DeleteStatesRequestTests.java | 2 +- .../learning/xapi/client/XapiClientTests.java | 24 +++++++++---------- .../java/dev/learning/xapi/model/Actor.java | 2 +- .../java/dev/learning/xapi/model/Agent.java | 6 +---- .../java/dev/learning/xapi/model/Group.java | 6 ++++- .../dev/learning/xapi/model/AgentTests.java | 13 ++++++++++ .../dev/learning/xapi/model/ContextTests.java | 2 +- .../dev/learning/xapi/model/GroupTests.java | 17 ++++++++++++- .../xapi/model/SubStatementTests.java | 2 +- .../resources/agent/agent_with_account.json | 3 +-- .../test/resources/agent/agent_with_mbox.json | 3 +-- .../agent/agent_with_mbox_sha1sum.json | 3 +-- .../test/resources/agent/agent_with_name.json | 3 +-- .../agent/agent_with_object_type.json | 5 ++++ .../resources/agent/agent_with_openid.json | 3 +-- .../src/test/resources/context/context.json | 3 +-- .../context_with_empty_registration.json | 3 +-- .../context_with_group_instructor.json | 2 -- .../context/context_without_registration.json | 3 +-- .../src/test/resources/group/group.json | 6 ++--- .../group_with_members_with_object_type.json | 18 ++++++++++++++ 22 files changed, 85 insertions(+), 46 deletions(-) create mode 100644 xapi-model/src/test/resources/agent/agent_with_object_type.json create mode 100644 xapi-model/src/test/resources/group/group_with_members_with_object_type.json diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java index 52011d41..d2ae2c59 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java @@ -137,7 +137,7 @@ void When() { // Then assertThat(url, is(URI.create( - "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java index 4a48a2fa..143c4f62 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java @@ -143,7 +143,7 @@ void when() { // Then assertThat(url, is(URI.create( - "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6"))); + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6"))); } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index 5f0feecc..24bb7692 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -92,7 +92,7 @@ void whenGettingASingleStateThenPathIsExpected() throws InterruptedException { // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } @Test @@ -133,7 +133,7 @@ void whenGettingASingleStateWithoutRegistrationThenPathIsExpected() throws Inter // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); } @Test @@ -232,7 +232,7 @@ void whenPostingASingleStateThenPathIsExpected() throws InterruptedException { // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } @Test @@ -329,7 +329,7 @@ void whenPostingASingleStateWithoutRegistrationThenPathIsExpected() throws Inter // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); } // Put Single State @@ -380,7 +380,7 @@ void whenPuttingASingleStateThenPathIsExpected() throws InterruptedException { // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } @Test @@ -477,7 +477,7 @@ void whenPuttingASingleStateWithoutRegistrationThenPathIsExpected() throws Inter // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark")); } // Deleting Single State @@ -520,7 +520,7 @@ void whenDeletingASingleStateThenPathIsExpected() throws InterruptedException { // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } @Test @@ -559,7 +559,7 @@ void whenDeletingASingleStateWithoutRegistrationThenPathIsExpected() throws Inte // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark")); } // Getting Multiple States @@ -606,7 +606,7 @@ void whenGettingMultipleStatesThenPathIsExpected() throws InterruptedException { // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6")); } @Test @@ -648,7 +648,7 @@ void whenGettingMultipleStatesWithoutRegistrationThenPathIsExpected() // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D")); } @Test @@ -737,7 +737,7 @@ void whenDeletingMultipleStatesThenPathIsExpected() throws InterruptedException // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6")); } @Test @@ -776,7 +776,7 @@ void whenDeletingMultipleStatesWithoutRegistrationThenPathIsExpected() // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22objectType%22%3A%22Agent%22%2C%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D")); + "/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D")); } } diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/Actor.java b/xapi-model/src/main/java/dev/learning/xapi/model/Actor.java index 3860246d..a6c86dbd 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/Actor.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/Actor.java @@ -32,7 +32,7 @@ @ToString @NoArgsConstructor @EqualsAndHashCode(exclude = "name") -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "objectType", visible = true, +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "objectType", visible = false, defaultImpl = Agent.class, include = As.EXISTING_PROPERTY) @JsonSubTypes({@JsonSubTypes.Type(value = Agent.class, name = "Agent"), @JsonSubTypes.Type(value = Agent.class, name = "Person"), diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/Agent.java b/xapi-model/src/main/java/dev/learning/xapi/model/Agent.java index dcaf5145..dde1c025 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/Agent.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/Agent.java @@ -7,7 +7,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import lombok.AllArgsConstructor; -import lombok.Builder.Default; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; @@ -30,12 +29,10 @@ @JsonSubTypes.Type(value = Agent.class, name = "Person")}) public class Agent extends Actor { - @Default - private final ObjectType objectType = ObjectType.AGENT; + ObjectType objectType; // **Warning** do not add fields that are not required by the xAPI specification. - /** * Builder for Agent. */ @@ -46,5 +43,4 @@ public abstract static class Builder> } - } diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/Group.java b/xapi-model/src/main/java/dev/learning/xapi/model/Group.java index adb98115..6e9f1d25 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/Group.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/Group.java @@ -6,6 +6,8 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import jakarta.validation.Valid; import java.util.ArrayList; import java.util.Arrays; @@ -22,7 +24,7 @@ * This class represents the xAPI Group object. * * @author Thomas Turrell-Croft - * + * * @see xAPI Group */ @Getter @@ -30,6 +32,8 @@ @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "objectType", visible = true, + include = As.EXISTING_PROPERTY) @JsonSubTypes({@JsonSubTypes.Type(value = Group.class, name = "Group")}) public class Group extends Actor { diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/AgentTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/AgentTests.java index 3355ee65..43ebfd86 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/AgentTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/AgentTests.java @@ -54,6 +54,19 @@ void whenDeserializingAgentWithoutObjectTypeThenResultIsInstanceOfAgent() throws } + @Test + void whenDeserializingAgentWithObjectTypeThenResultIsInstanceOfAgent() throws IOException { + + final File file = ResourceUtils.getFile("classpath:agent/agent_with_object_type.json"); + + // When Deserializing Agent Without Object Type + final Agent result = objectMapper.readValue(file, Agent.class); + + // Then Result Is Instance Of Agent + assertThat(result, instanceOf(Agent.class)); + + } + @Test void whenDeserializingAgentWithNameThenNameIsExpected() throws IOException { diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/ContextTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/ContextTests.java index 4493d2bb..e54ff72f 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/ContextTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/ContextTests.java @@ -268,7 +268,7 @@ void whenCallingToStringThenResultIsExpected() throws IOException { // Then Result Is Expected assertThat(result, is( - "Context(registration=1d527164-ed0d-4b1d-9f9b-39aab0e4a089, instructor=Agent(super=Actor(name=Andrew Downes, mbox=mailto:andrew@example.co.uk, mboxSha1sum=null, openid=null, account=null), objectType=AGENT), team=Group(super=Actor(name=Example Group, mbox=null, mboxSha1sum=null, openid=null, account=null), objectType=GROUP, member=null), contextActivities=ContextActivities(parent=[Activity(objectType=ACTIVITY, id=https://example.com/activity/1, definition=null)], grouping=[Activity(objectType=ACTIVITY, id=https://example.com/activity/2, definition=null)], category=[Activity(objectType=ACTIVITY, id=https://example.com/activity/3, definition=null)], other=[Activity(objectType=ACTIVITY, id=https://example.com/activity/4, definition=null)]), revision=revision, platform=platform, language=en, statement=StatementReference(objectType=null, id=e9b6b9ed-ef48-4986-9b86-2ef697578bf7), extensions={http://url=www.example.com})")); + "Context(registration=1d527164-ed0d-4b1d-9f9b-39aab0e4a089, instructor=Agent(super=Actor(name=Andrew Downes, mbox=mailto:andrew@example.co.uk, mboxSha1sum=null, openid=null, account=null), objectType=null), team=Group(super=Actor(name=Example Group, mbox=null, mboxSha1sum=null, openid=null, account=null), objectType=GROUP, member=null), contextActivities=ContextActivities(parent=[Activity(objectType=ACTIVITY, id=https://example.com/activity/1, definition=null)], grouping=[Activity(objectType=ACTIVITY, id=https://example.com/activity/2, definition=null)], category=[Activity(objectType=ACTIVITY, id=https://example.com/activity/3, definition=null)], other=[Activity(objectType=ACTIVITY, id=https://example.com/activity/4, definition=null)]), revision=revision, platform=platform, language=en, statement=StatementReference(objectType=null, id=e9b6b9ed-ef48-4986-9b86-2ef697578bf7), extensions={http://url=www.example.com})")); } diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/GroupTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/GroupTests.java index f87c2a39..cd40484e 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/GroupTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/GroupTests.java @@ -40,6 +40,21 @@ void whenDeserializingGroupThenResultIsInstanceOfGroup() throws IOException { } + @Test + void whenDeserializingGroupWithMembersWithObjectTypeThenResultIsInstanceOfGroup() + throws IOException { + + final File file = + ResourceUtils.getFile("classpath:group/group_with_members_with_object_type.json"); + + // When Deserializing Group With Members With Object Type + final Group result = objectMapper.readValue(file, Group.class); + + // Then Result Is Instance Of Group + assertThat(result, instanceOf(Group.class)); + + } + @Test void whenDeserializingGroupThenMemberIsInstanceOfAgent() throws IOException { @@ -87,7 +102,7 @@ void whenCallingToStringThenResultIsExpected() throws IOException { // Then Result Is Expected assertThat(result, is( - "Group(super=Actor(name=Example Group, mbox=null, mboxSha1sum=null, openid=null, account=Account(homePage=http://example.com/homePage, name=GroupAccount)), objectType=GROUP, member=[Agent(super=Actor(name=Member 1, mbox=mailto:member1@example.com, mboxSha1sum=null, openid=null, account=null), objectType=AGENT), Agent(super=Actor(name=Member 2, mbox=null, mboxSha1sum=null, openid=https://example.com/openId, account=null), objectType=AGENT)])")); + "Group(super=Actor(name=Example Group, mbox=null, mboxSha1sum=null, openid=null, account=Account(homePage=http://example.com/homePage, name=GroupAccount)), objectType=GROUP, member=[Agent(super=Actor(name=Member 1, mbox=mailto:member1@example.com, mboxSha1sum=null, openid=null, account=null), objectType=null), Agent(super=Actor(name=Member 2, mbox=null, mboxSha1sum=null, openid=https://example.com/openId, account=null), objectType=null)])")); } diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/SubStatementTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/SubStatementTests.java index d601f1e3..1fb74bcc 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/SubStatementTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/SubStatementTests.java @@ -350,7 +350,7 @@ void whenCallingToStringThenResultIsExpected() throws IOException { // Then Result Is Expected assertThat(result, is( - "SubStatement(objectType=null, actor=Agent(super=Actor(name=null, mbox=mailto:agent@example.com, mboxSha1sum=null, openid=null, account=null), objectType=AGENT), verb=Verb(id=http://example.com/confirmed, display={en=confirmed}), object=StatementReference(objectType=STATEMENTREF, id=9e13cefd-53d3-4eac-b5ed-2cf6693903bb), result=Result(score=Score(scaled=1.0, raw=1.0, min=0.0, max=5.0), success=true, completion=true, response=test, duration=P1D, extensions=null), context=Context(registration=6d969975-8d7e-4506-ac19-877c57f2921a, instructor=Agent(super=Actor(name=null, mbox=mailto:agent@example.com, mboxSha1sum=null, openid=null, account=null), objectType=AGENT), team=Group(super=Actor(name=Example Group, mbox=null, mboxSha1sum=null, openid=null, account=null), objectType=GROUP, member=null), contextActivities=ContextActivities(parent=[Activity(objectType=ACTIVITY, id=http://www.example.co.uk/exampleactivity, definition=null)], grouping=[Activity(objectType=ACTIVITY, id=http://www.example.co.uk/exampleactivity, definition=null)], category=[Activity(objectType=ACTIVITY, id=http://www.example.co.uk/exampleactivity, definition=null)], other=[Activity(objectType=ACTIVITY, id=http://www.example.co.uk/exampleactivity, definition=null)]), revision=revision, platform=platform, language=en, statement=StatementReference(objectType=null, id=9e13cefd-53d3-4eac-b5ed-2cf6693903bb), extensions={http://url=www.example.com}), timestamp=2015-11-18T11:17:00Z, attachments=[Attachment(usageType=http://example.com, display={en=value}, description={en=value}, contentType=file, length=123, sha2=123, fileUrl=http://example.com)])")); + "SubStatement(objectType=null, actor=Agent(super=Actor(name=null, mbox=mailto:agent@example.com, mboxSha1sum=null, openid=null, account=null), objectType=null), verb=Verb(id=http://example.com/confirmed, display={en=confirmed}), object=StatementReference(objectType=STATEMENTREF, id=9e13cefd-53d3-4eac-b5ed-2cf6693903bb), result=Result(score=Score(scaled=1.0, raw=1.0, min=0.0, max=5.0), success=true, completion=true, response=test, duration=P1D, extensions=null), context=Context(registration=6d969975-8d7e-4506-ac19-877c57f2921a, instructor=Agent(super=Actor(name=null, mbox=mailto:agent@example.com, mboxSha1sum=null, openid=null, account=null), objectType=null), team=Group(super=Actor(name=Example Group, mbox=null, mboxSha1sum=null, openid=null, account=null), objectType=GROUP, member=null), contextActivities=ContextActivities(parent=[Activity(objectType=ACTIVITY, id=http://www.example.co.uk/exampleactivity, definition=null)], grouping=[Activity(objectType=ACTIVITY, id=http://www.example.co.uk/exampleactivity, definition=null)], category=[Activity(objectType=ACTIVITY, id=http://www.example.co.uk/exampleactivity, definition=null)], other=[Activity(objectType=ACTIVITY, id=http://www.example.co.uk/exampleactivity, definition=null)]), revision=revision, platform=platform, language=en, statement=StatementReference(objectType=null, id=9e13cefd-53d3-4eac-b5ed-2cf6693903bb), extensions={http://url=www.example.com}), timestamp=2015-11-18T11:17:00Z, attachments=[Attachment(usageType=http://example.com, display={en=value}, description={en=value}, contentType=file, length=123, sha2=123, fileUrl=http://example.com)])")); } diff --git a/xapi-model/src/test/resources/agent/agent_with_account.json b/xapi-model/src/test/resources/agent/agent_with_account.json index 2023404c..9213e34e 100644 --- a/xapi-model/src/test/resources/agent/agent_with_account.json +++ b/xapi-model/src/test/resources/agent/agent_with_account.json @@ -3,6 +3,5 @@ "account": { "name": "another", "homePage": "https://www.example.com" - }, - "objectType": "Agent" + } } diff --git a/xapi-model/src/test/resources/agent/agent_with_mbox.json b/xapi-model/src/test/resources/agent/agent_with_mbox.json index d9122c52..bd7805f0 100644 --- a/xapi-model/src/test/resources/agent/agent_with_mbox.json +++ b/xapi-model/src/test/resources/agent/agent_with_mbox.json @@ -1,5 +1,4 @@ { "name": "A N Other", - "mbox": "mailto:other@example.com", - "objectType": "Agent" + "mbox": "mailto:other@example.com" } diff --git a/xapi-model/src/test/resources/agent/agent_with_mbox_sha1sum.json b/xapi-model/src/test/resources/agent/agent_with_mbox_sha1sum.json index 71a3422b..2b4f2421 100644 --- a/xapi-model/src/test/resources/agent/agent_with_mbox_sha1sum.json +++ b/xapi-model/src/test/resources/agent/agent_with_mbox_sha1sum.json @@ -1,5 +1,4 @@ { "name": "A N Other", - "mbox_sha1sum": "1234", - "objectType": "Agent" + "mbox_sha1sum": "1234" } diff --git a/xapi-model/src/test/resources/agent/agent_with_name.json b/xapi-model/src/test/resources/agent/agent_with_name.json index d9122c52..bd7805f0 100644 --- a/xapi-model/src/test/resources/agent/agent_with_name.json +++ b/xapi-model/src/test/resources/agent/agent_with_name.json @@ -1,5 +1,4 @@ { "name": "A N Other", - "mbox": "mailto:other@example.com", - "objectType": "Agent" + "mbox": "mailto:other@example.com" } diff --git a/xapi-model/src/test/resources/agent/agent_with_object_type.json b/xapi-model/src/test/resources/agent/agent_with_object_type.json new file mode 100644 index 00000000..00adbd3b --- /dev/null +++ b/xapi-model/src/test/resources/agent/agent_with_object_type.json @@ -0,0 +1,5 @@ +{ + "name": "A N Other", + "mbox": "mailto:other@example.com", + "objectType": "Agent" +} diff --git a/xapi-model/src/test/resources/agent/agent_with_openid.json b/xapi-model/src/test/resources/agent/agent_with_openid.json index 68ac4f29..cc967d90 100644 --- a/xapi-model/src/test/resources/agent/agent_with_openid.json +++ b/xapi-model/src/test/resources/agent/agent_with_openid.json @@ -1,5 +1,4 @@ { "name": "A N Other", - "openid": "1234", - "objectType": "Agent" + "openid": "1234" } diff --git a/xapi-model/src/test/resources/context/context.json b/xapi-model/src/test/resources/context/context.json index 9146036b..7e646aff 100644 --- a/xapi-model/src/test/resources/context/context.json +++ b/xapi-model/src/test/resources/context/context.json @@ -5,8 +5,7 @@ "language": "en", "instructor": { "name": "Andrew Downes", - "mbox": "mailto:andrew@example.co.uk", - "objectType": "Agent" + "mbox": "mailto:andrew@example.co.uk" }, "team": { "name": "Example Group", diff --git a/xapi-model/src/test/resources/context/context_with_empty_registration.json b/xapi-model/src/test/resources/context/context_with_empty_registration.json index e72ab073..990ffb74 100644 --- a/xapi-model/src/test/resources/context/context_with_empty_registration.json +++ b/xapi-model/src/test/resources/context/context_with_empty_registration.json @@ -5,8 +5,7 @@ "language": "en", "instructor": { "name": "Andrew Downes", - "mbox": "mailto:andrew@example.co.uk", - "objectType": "Agent" + "mbox": "mailto:andrew@example.co.uk" }, "team": { "name": "Example Group", diff --git a/xapi-model/src/test/resources/context/context_with_group_instructor.json b/xapi-model/src/test/resources/context/context_with_group_instructor.json index 788d38e4..1e69c06e 100644 --- a/xapi-model/src/test/resources/context/context_with_group_instructor.json +++ b/xapi-model/src/test/resources/context/context_with_group_instructor.json @@ -3,12 +3,10 @@ "objectType":"Group", "member":[ { - "objectType":"Agent", "name":"Leader 1", "mbox":"mailto:leader1@example.com" }, { - "objectType":"Agent", "name":"Leader 2", "mbox":"mailto:leader2@example.com" } diff --git a/xapi-model/src/test/resources/context/context_without_registration.json b/xapi-model/src/test/resources/context/context_without_registration.json index 68e1ea8b..cd324ee9 100644 --- a/xapi-model/src/test/resources/context/context_without_registration.json +++ b/xapi-model/src/test/resources/context/context_without_registration.json @@ -4,8 +4,7 @@ "language": "en", "instructor": { "name": "Andrew Downes", - "mbox": "mailto:andrew@example.co.uk", - "objectType": "Agent" + "mbox": "mailto:andrew@example.co.uk" }, "team": { "name": "Example Group", diff --git a/xapi-model/src/test/resources/group/group.json b/xapi-model/src/test/resources/group/group.json index bdd83d56..3d7463ab 100644 --- a/xapi-model/src/test/resources/group/group.json +++ b/xapi-model/src/test/resources/group/group.json @@ -8,13 +8,11 @@ "member": [ { "name": "Member 1", - "mbox": "mailto:member1@example.com", - "objectType": "Agent" + "mbox": "mailto:member1@example.com" }, { "name": "Member 2", - "openid": "https://example.com/openId", - "objectType": "Agent" + "openid": "https://example.com/openId" } ] } diff --git a/xapi-model/src/test/resources/group/group_with_members_with_object_type.json b/xapi-model/src/test/resources/group/group_with_members_with_object_type.json new file mode 100644 index 00000000..3d7463ab --- /dev/null +++ b/xapi-model/src/test/resources/group/group_with_members_with_object_type.json @@ -0,0 +1,18 @@ +{ + "name": "Example Group", + "account": { + "homePage": "http://example.com/homePage", + "name": "GroupAccount" + }, + "objectType": "Group", + "member": [ + { + "name": "Member 1", + "mbox": "mailto:member1@example.com" + }, + { + "name": "Member 2", + "openid": "https://example.com/openId" + } + ] +} From bbc0b72c74db4b32af04d8e11da59addff6e3a6e Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 13:02:26 +0000 Subject: [PATCH 55/74] private --- xapi-model/src/main/java/dev/learning/xapi/model/Agent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/Agent.java b/xapi-model/src/main/java/dev/learning/xapi/model/Agent.java index dde1c025..17558360 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/Agent.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/Agent.java @@ -29,7 +29,7 @@ @JsonSubTypes.Type(value = Agent.class, name = "Person")}) public class Agent extends Actor { - ObjectType objectType; + private ObjectType objectType; // **Warning** do not add fields that are not required by the xAPI specification. From bb0c52762702a406b7477b03081e5cc0a65d5372 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 13:03:59 +0000 Subject: [PATCH 56/74] tip --- xapi-model/src/test/resources/agent/agent_with_object_type.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-model/src/test/resources/agent/agent_with_object_type.json b/xapi-model/src/test/resources/agent/agent_with_object_type.json index 00adbd3b..48f99f3a 100644 --- a/xapi-model/src/test/resources/agent/agent_with_object_type.json +++ b/xapi-model/src/test/resources/agent/agent_with_object_type.json @@ -1,5 +1,5 @@ { "name": "A N Other", "mbox": "mailto:other@example.com", - "objectType": "Agent" + "objectType": "Agent" } From 65c2c78c8b08e53ca47adc3e5636f5783339df2f Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 13:05:49 +0000 Subject: [PATCH 57/74] tip --- xapi-model/src/test/resources/agent/agent_with_object_type.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-model/src/test/resources/agent/agent_with_object_type.json b/xapi-model/src/test/resources/agent/agent_with_object_type.json index 48f99f3a..d9122c52 100644 --- a/xapi-model/src/test/resources/agent/agent_with_object_type.json +++ b/xapi-model/src/test/resources/agent/agent_with_object_type.json @@ -1,5 +1,5 @@ { "name": "A N Other", "mbox": "mailto:other@example.com", - "objectType": "Agent" + "objectType": "Agent" } From b80d8e30a4c652810fcaf52975c962f1b071ddeb Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 13:07:14 +0000 Subject: [PATCH 58/74] tip --- xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java index 48a6b7b4..b3942c7b 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java @@ -6,6 +6,4 @@ @SpringBootApplication public class TestApp { - - } From c0ec5128252bb902a2f3d547766a4d49f0cdcf2d Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 13:12:08 +0000 Subject: [PATCH 59/74] tip --- .../src/test/java/dev/learning/xapi/client/TestApp.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java index b3942c7b..26792bc9 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; From 953fd64ebacc6b0cc6f43120fc1408a0a6f75007 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 17:40:12 +0000 Subject: [PATCH 60/74] tip --- .../xapi/client/DeleteStateRequestTests.java | 45 ++++- .../xapi/client/DeleteStatesRequestTests.java | 40 ++++- .../xapi/client/GetStateRequestTests.java | 125 +++++++++++++ .../xapi/client/GetStatesRequestTests.java | 164 ++++++++++++++++++ .../xapi/client/PostStateRequestTests.java | 90 ++++++++-- .../xapi/client/PutStateRequestTests.java | 88 ++++++++-- 6 files changed, 502 insertions(+), 50 deletions(-) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java index d2ae2c59..ad1f3eaf 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java @@ -15,7 +15,6 @@ import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.web.util.UriBuilder; import org.springframework.web.util.UriComponentsBuilder; /** @@ -114,11 +113,9 @@ void whenBuildingDeleteStateRequestWithoutStateIdThenExceptionIsThrown() { } @Test - void When() { + void givenDeleteStateRequestWithAllParametersWhenGettingURLThenResultIsExpected() { - UriBuilder builder = UriComponentsBuilder.fromUriString("https://example.com/xapi/"); - - // When + // Given DeleteStateRequest With All Parameters DeleteStateRequest request = DeleteStateRequest.builder() .activityId("https://example.com/activity/1") @@ -133,14 +130,46 @@ void When() { Map queryParams = new HashMap<>(); - URI url = request.url(builder, queryParams).build(queryParams); + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); - // Then - assertThat(url, is(URI.create( + // Then Result Is Expected + assertThat(result, is(URI.create( "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); } + @Test + void givenDeleteStateRequestWithoutRegistrationWhenGettingURLThenResultIsExpected() { + + // Given DeleteStateRequest Without Registration + DeleteStateRequest request = DeleteStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark"))); + + } + + + } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java index 143c4f62..43843060 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStatesRequestTests.java @@ -14,7 +14,6 @@ import java.util.UUID; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.web.util.UriBuilder; import org.springframework.web.util.UriComponentsBuilder; /** @@ -122,11 +121,9 @@ void whenBuildingDeleteStatesRequestWithoutAgentThenExceptionIsThrown() { } @Test - void when() { + void givenDeleteStatesRequestWithAllParametersWhenGettingURLThenResultIsExpected() { - UriBuilder builder = UriComponentsBuilder.fromUriString("https://example.com/xapi/"); - - // When + // Given DeleteStatesRequest With All Parameters DeleteStatesRequest request = DeleteStatesRequest.builder() .activityId("https://example.com/activity/1") @@ -139,12 +136,41 @@ void when() { Map queryParams = new HashMap<>(); - URI url = request.url(builder, queryParams).build(queryParams); + // When Getting URL + URI url = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); - // Then + // Then Result Is Expected assertThat(url, is(URI.create( "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6"))); } + + @Test + void givenDeleteStatesRequestWithoutRegistrationWhenGettingURLThenResultIsExpected() { + + // Given DeleteStatesRequest Without Registration + DeleteStatesRequest request = DeleteStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI url = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(url, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D"))); + + } + } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java index 939e78e3..2bc0f9b8 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java @@ -4,10 +4,17 @@ package dev.learning.xapi.client; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import dev.learning.xapi.client.GetStateRequest.Builder; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.web.util.UriComponentsBuilder; /** * GetStateRequest Tests. @@ -34,7 +41,125 @@ void whenBuildingGetStateRequestWithAllParametersThenNoExceptionIsThrown() { // Then No Exception Is Thrown assertDoesNotThrow(() -> builder.build()); + } + + @Test + void whenBuildingGetStateRequestWithoutRegistrationThenNoExceptionIsThrown() { + + // When Building GetStateRequest Without Registration + Builder builder = GetStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark"); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); } + @Test + void whenBuildingGetStateRequestWithoutActivityIdThenNullPointerExceptionIsThrown() { + + // When Building GetStateRequest Without activityId + Builder builder = GetStateRequest.builder() + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark"); + + // Then Null Pointer Exception Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); + + } + + @Test + void whenBuildingGetStateRequestWithoutAgentThenNullPointerExceptionIsThrown() { + + // When Building GetStateRequest Without Agent + Builder builder = GetStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .stateId("bookmark"); + + // Then Null Pointer Exception Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); + + } + + @Test + void whenBuildingGetStateRequestWithoutStateIdThenNullPointerExceptionIsThrown() { + + // When Building GetStateRequest Without StateId + Builder builder = GetStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")); + + // Then Null Pointer Exception Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); + + } + + @Test + void givenGetStateRequestWithAllParametersWhenGettingURLThenResultIsExpected() { + + // Given GetStateRequest With All Parameters + GetStateRequest request = GetStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); + + } + + @Test + void givenGetStateRequestWithoutRegistrationWhenGettingURLThenResultIsExpected() { + + // Given GetStateRequest Without Registration + GetStateRequest request = GetStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark"))); + + } + + } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java index aedafe02..743911ca 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java @@ -4,10 +4,18 @@ package dev.learning.xapi.client; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import dev.learning.xapi.client.GetStatesRequest.Builder; +import java.net.URI; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.web.util.UriComponentsBuilder; /** * GetStatesRequest Tests. @@ -27,12 +35,168 @@ void whenBuildingGetStatesRequestWithAllParametersThenNoExceptionIsThrown() { .agent(a -> a.name("A N Other").mbox("another@example.com")) + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .since(Instant.now()); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + + @Test + void whenBuildingGetStatesRequestWithoutSinceParameterThenNoExceptionIsThrown() { + + // When Building GetStatesRequest Without Since Parameter + Builder builder = GetStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6"); // Then No Exception Is Thrown assertDoesNotThrow(() -> builder.build()); + } + + @Test + void whenBuildingGetStatesRequestWithoutRegistrationParameterThenNoExceptionIsThrown() { + + // When Building GetStatesRequest Without Registration Parameter + Builder builder = GetStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + + @Test + void whenBuildingGetStatesRequestWithRequiredParametersThenNoExceptionIsThrown() { + + // When Building GetStatesRequest With Required Parameters + Builder builder = GetStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + + @Test + void whenBuildingGetStatesRequestWithoutActivityIdThenNullPointerExceptionIsThrown() { + + // When Building GetStatesRequest Without ActivityId + Builder builder = GetStatesRequest.builder() + + .agent(a -> a.name("A N Other").mbox("another@example.com")); + + // Then Null Pointer Exception Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); } + @Test + void whenBuildingGetStatesRequestWithoutAgentThenNullPointerExceptionIsThrown() { + + // When Building GetStatesRequest Without Agent + Builder builder = GetStatesRequest.builder() + + .activityId("https://example.com/activity/1"); + + // Then Null Pointer Exception Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); + + } + + @Test + void givenGetStatesRequestWithAllParametersWhenGettingURLThenResultIsExpected() { + + // Given GetStatesRequest With All Parameters + GetStatesRequest request = GetStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .since(Instant.parse("2016-01-01T00:00:00Z")) + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&since=2016-01-01T00:00:00Z"))); + + } + + @Test + void givenGetStatesRequestWithoutRegistrationParameterWhenGettingURLThenResultIsExpected() { + + // Given GetStatesRequest Without Registration Parameter + GetStatesRequest request = GetStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D"))); + + } + + @Test + void givenGetStatesRequestWithoutSinceParameterWhenGettingURLThenResultIsExpected() { + + // Given GetStatesRequest Without Since Parameter + GetStatesRequest request = GetStatesRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6"))); + + } + + } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java index 85b24044..2f770a27 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java @@ -4,12 +4,19 @@ package dev.learning.xapi.client; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import dev.learning.xapi.client.PostStateRequest.Builder; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.web.util.UriComponentsBuilder; /** - * PutStateRequest Tests. + * PostStateRequest Tests. * * @author Thomas Turrell-Croft */ @@ -17,34 +24,85 @@ class PostStateRequestTests { @Test - void whenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { + void whenBuildingPostStateRequestWithAllParametersThenNoExceptionIsThrown() { - // When Building PutStateRequest With All Parameters - assertDoesNotThrow(() -> { - PutStateRequest.builder() + // When Building PostStateRequest With All Parameters + Builder builder = PostStateRequest.builder() - // Parameters + .activityId("https://example.com/activity/1") - .activityId("https://example.com/activity/1") + .agent(a -> a.name("A N Other").mbox("another@example.com")) - .agent(a -> a.name("A N Other").mbox("another@example.com")) + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + .stateId("bookmark") - .stateId("bookmark") + .state("Hello World!"); - // Body + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); - .state("Hello World!") + } - // Headers + @Test + void givenPostStateRequestWithAllParametersWhenGettingURLThenResultIsExpected() { - .build(); + // Given PostStateRequest With All Parameters + PostStateRequest request = PostStateRequest.builder() - }); + .activityId("https://example.com/activity/1") - // Then No Exception Is Thrown + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!") + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); } + @Test + void givenPostStateRequestWithoutRegistrationWhenGettingURLThenResultIsExpected() { + + // Given PostStateRequest Without Registration + PostStateRequest request = PostStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .state("Hello World!") + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark"))); + + } + + } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java index 9679cf8f..cf146b7e 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java @@ -4,9 +4,16 @@ package dev.learning.xapi.client; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import dev.learning.xapi.client.PutStateRequest.Builder; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.web.util.UriComponentsBuilder; /** * PutStateRequest Tests. @@ -16,41 +23,84 @@ @DisplayName("PutStateRequest Tests") class PutStateRequestTests { + @Test + void whenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building PutStateRequest With All Parameters + Builder builder = PutStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - // activityId | Required - // agent | Required - // registration | Optional - // stateId | Required + .stateId("bookmark") + .state("Hello World!"); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } @Test - void whenBuildingPutStateRequestWithAllParametersThenNoExceptionIsThrown() { + void givenPutStateRequestWithAllParametersWhenGettingURLThenResultIsExpected() { - // When Building PutStateRequest With All Parameters - assertDoesNotThrow(() -> { - PutStateRequest.builder() + // Given PutStateRequest With All Parameters + PutStateRequest request = PutStateRequest.builder() - // Parameters + .activityId("https://example.com/activity/1") - .activityId("https://example.com/activity/1") + .agent(a -> a.name("A N Other").mbox("another@example.com")) - .agent(a -> a.name("A N Other").mbox("another@example.com")) + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + .stateId("bookmark") - .stateId("bookmark") + .state("Hello World!") - // Body + .build(); - .state("Hello World!") + Map queryParams = new HashMap<>(); - // Headers + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); - .build(); + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D®istration=67828e3a-d116-4e18-8af3-2d2c59e27be6&stateId=bookmark"))); - }); + } - // Then No Exception Is Thrown + @Test + void givenPutStateRequestWithoutRegistrationWhenGettingURLThenResultIsExpected() { + + // Given PutStateRequest Without Registration + PutStateRequest request = PutStateRequest.builder() + + .activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .stateId("bookmark") + + .state("Hello World!") + + .build(); + + Map queryParams = new HashMap<>(); + + // When Getting URL + URI result = + request.url(UriComponentsBuilder.fromUriString("https://example.com/xapi/"), queryParams) + .build(queryParams); + + // Then Result Is Expected + assertThat(result, is(URI.create( + "https://example.com/xapi/activities/state?activityId=https%3A%2F%2Fexample.com%2Factivity%2F1&agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22another%40example.com%22%7D&stateId=bookmark"))); } From df40e91cb742e07da64a76f490233f55bb753a9c Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 17:52:00 +0000 Subject: [PATCH 61/74] sonar test --- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index f8ff2271..05ab9f05 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -1,5 +1,6 @@ package dev.learning.xapi.client; +import dev.learning.xapi.model.Agent; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -79,6 +80,9 @@ public Mono> getState(GetStateRequest request, Class bo public Mono> getState(Consumer> request, Class bodyType) { + + final Agent.Builder builder2 = Agent.builder(); + final GetStateRequest.Builder builder = GetStateRequest.builder(); request.accept(builder); From 1a38b21e915fb55fcf799d95ea0b18893a35c253 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 17:54:45 +0000 Subject: [PATCH 62/74] tip --- .../dev/learning/xapi/client/DeleteStateRequestTests.java | 4 ---- .../java/dev/learning/xapi/client/GetStateRequestTests.java | 1 - .../java/dev/learning/xapi/client/GetStatesRequestTests.java | 1 - .../java/dev/learning/xapi/client/PostStateRequestTests.java | 1 - .../test/java/dev/learning/xapi/client/XapiClientTests.java | 2 -- 5 files changed, 9 deletions(-) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java index ad1f3eaf..a22d237c 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java @@ -168,8 +168,4 @@ void givenDeleteStateRequestWithoutRegistrationWhenGettingURLThenResultIsExpecte } - - } - - diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java index 2bc0f9b8..4b173854 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java @@ -161,5 +161,4 @@ void givenGetStateRequestWithoutRegistrationWhenGettingURLThenResultIsExpected() } - } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java index 743911ca..9da0927f 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java @@ -198,5 +198,4 @@ void givenGetStatesRequestWithoutSinceParameterWhenGettingURLThenResultIsExpecte } - } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java index 2f770a27..ec49b038 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java @@ -104,5 +104,4 @@ void givenPostStateRequestWithoutRegistrationWhenGettingURLThenResultIsExpected( } - } diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index 24bb7692..e14045c0 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -780,5 +780,3 @@ void whenDeletingMultipleStatesWithoutRegistrationThenPathIsExpected() } } - - From 94d7525e360ef8c2189cc77ae57cfb4cca5b6dd7 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 17:58:07 +0000 Subject: [PATCH 63/74] hearders --- .../main/java/dev/learning/xapi/client/DeleteStateRequest.java | 3 +++ .../java/dev/learning/xapi/client/DeleteStatesRequest.java | 3 +++ .../main/java/dev/learning/xapi/client/GetStateRequest.java | 3 +++ .../main/java/dev/learning/xapi/client/GetStatesRequest.java | 3 +++ .../main/java/dev/learning/xapi/client/PostStateRequest.java | 3 +++ .../main/java/dev/learning/xapi/client/PutStateRequest.java | 3 +++ .../src/main/java/dev/learning/xapi/client/Request.java | 3 +++ .../src/main/java/dev/learning/xapi/client/StateRequest.java | 3 +++ .../src/main/java/dev/learning/xapi/client/StatesRequest.java | 3 +++ .../src/main/java/dev/learning/xapi/client/XapiClient.java | 3 +++ .../java/dev/learning/xapi/client/DeleteStateRequestTests.java | 2 -- .../java/dev/learning/xapi/client/GetStateRequestTests.java | 1 - .../java/dev/learning/xapi/client/GetStatesRequestTests.java | 1 - .../java/dev/learning/xapi/client/PostStateRequestTests.java | 1 - .../java/dev/learning/xapi/client/PutStateRequestTests.java | 1 - .../src/test/java/dev/learning/xapi/client/TestApp.java | 1 - .../test/java/dev/learning/xapi/client/XapiClientTests.java | 1 - 17 files changed, 30 insertions(+), 8 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index 07dc6f61..a765dd96 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import lombok.experimental.SuperBuilder; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index f0d502f4..7a859e62 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import lombok.experimental.SuperBuilder; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index 928b150f..ba0b16fd 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import lombok.experimental.SuperBuilder; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index f3cf4206..6626bbbc 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import java.time.Instant; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index d52cda6f..4b94f311 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import lombok.Builder.Default; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index c0914644..e884a813 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import lombok.Builder.Default; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 043d48db..03e1ca49 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import java.util.Map; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index b9180816..58142abb 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import java.util.Map; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index b3bc4fda..4513fb7d 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 05ab9f05..6db1516c 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -1,3 +1,6 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ package dev.learning.xapi.client; import dev.learning.xapi.model.Agent; diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java index a22d237c..229e3b35 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/DeleteStateRequestTests.java @@ -1,10 +1,8 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ - package dev.learning.xapi.client; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java index 4b173854..6b8801a6 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStateRequestTests.java @@ -1,7 +1,6 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ - package dev.learning.xapi.client; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java index 9da0927f..8328918a 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatesRequestTests.java @@ -1,7 +1,6 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ - package dev.learning.xapi.client; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java index ec49b038..2f92d584 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PostStateRequestTests.java @@ -1,7 +1,6 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ - package dev.learning.xapi.client; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java index cf146b7e..fe9bd0ff 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/PutStateRequestTests.java @@ -1,7 +1,6 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ - package dev.learning.xapi.client; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java index 26792bc9..e03afd41 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/TestApp.java @@ -1,7 +1,6 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ - package dev.learning.xapi.client; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index e14045c0..d60c8e6a 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -1,7 +1,6 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ - package dev.learning.xapi.client; import static org.hamcrest.MatcherAssert.assertThat; From 75931b75c44f6c1cb7cb26bc4bbca554e8fb2405 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 18:01:17 +0000 Subject: [PATCH 64/74] d --- .../src/main/java/dev/learning/xapi/client/StatesRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 4513fb7d..49f9e418 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -29,7 +29,7 @@ @Getter abstract class StatesRequest extends Request { - private final ObjectMapper objectMapper = new ObjectMapper(); + private final static ObjectMapper objectMapper = new ObjectMapper(); /** * The activityId query parameter. From bea4f39540c593dad3739939c4809f2b5499caea Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 18:10:08 +0000 Subject: [PATCH 65/74] tip --- .../java/dev/learning/xapi/client/GetStateRequest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index ba0b16fd..d626699f 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -23,4 +23,14 @@ protected HttpMethod getMethod() { return HttpMethod.GET; } + /** + * Builder for GetStateRequest. + */ + public abstract static class Builder> + extends StateRequest.Builder { + + // This static class extends the lombok builder. + + } + } From 43afed4e2b6cb37d14a7c88be890a988833289cd Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 18:20:20 +0000 Subject: [PATCH 66/74] stuff --- README.md | 17 +++++++++++------ .../xapi/client/DeleteStateRequest.java | 1 + .../xapi/client/DeleteStatesRequest.java | 1 + .../learning/xapi/client/GetStateRequest.java | 1 + .../xapi/client/GetStatesRequest.java | 1 + .../xapi/client/PostStateRequest.java | 1 + .../learning/xapi/client/PutStateRequest.java | 1 + .../dev/learning/xapi/client/Request.java | 1 + .../learning/xapi/client/StateRequest.java | 1 + .../learning/xapi/client/StatesRequest.java | 3 ++- .../dev/learning/xapi/client/XapiClient.java | 1 + .../learning/xapi/client/XapiClientTests.java | 19 +++++++++++++++++++ 12 files changed, 41 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9f62e77c..1cfc1544 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,21 @@ xAPI Java helps you to create applications that send or receive xAPI [Statements ## xAPI Java Client -```java -client.putStateRequest(r -> r.activityId(activityId) +### Getting a state + + - .agent(agent) - .stateId("resume") +```java +client.getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) - .body(body) + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - .contentType(contentType)); + .stateId("bookmark"), String.class) + + .block(); ``` ## xAPI Java Model diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index a765dd96..80a61084 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import lombok.experimental.SuperBuilder; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index 7a859e62..4a18e5a7 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import lombok.experimental.SuperBuilder; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index d626699f..097e31ad 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import lombok.experimental.SuperBuilder; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index 6626bbbc..4cb1aa82 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import java.time.Instant; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index 4b94f311..f0d503ab 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import lombok.Builder.Default; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index e884a813..2fb9ab82 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import lombok.Builder.Default; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 03e1ca49..6e092dbf 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import java.util.Map; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index 58142abb..94669f4f 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import java.util.Map; diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index 49f9e418..e7bff8b7 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import com.fasterxml.jackson.core.JsonProcessingException; @@ -29,7 +30,7 @@ @Getter abstract class StatesRequest extends Request { - private final static ObjectMapper objectMapper = new ObjectMapper(); + private static final ObjectMapper objectMapper = new ObjectMapper(); /** * The activityId query parameter. diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 6db1516c..0cfb5a92 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -1,6 +1,7 @@ /* * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. */ + package dev.learning.xapi.client; import dev.learning.xapi.model.Agent; diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index d60c8e6a..f554a388 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -73,6 +73,25 @@ void whenGettingASingleStateThenMethodIsGet() throws InterruptedException { assertThat(recordedRequest.getMethod(), is("GET")); } + + @Test + void d() throws InterruptedException { + + + final ResponseEntity request = + client.getState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark"), String.class).block(); + + final String state = request.getBody(); + + + } + @Test void whenGettingASingleStateThenPathIsExpected() throws InterruptedException { From f7c93286fc618b2fcd205ed52d99e17169e78137 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 19:13:01 +0000 Subject: [PATCH 67/74] documentation --- README.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1cfc1544..bd947982 100644 --- a/README.md +++ b/README.md @@ -2,28 +2,110 @@ xAPI Java helps you to create applications that send or receive xAPI [Statements](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#statements) or [Documents](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#10-documents). +There are two projects in this [Monorepo](https://en.wikipedia.org/wiki/Monorepo), The xAPI Java Client and the xAPI Java Model. + +Both the xAPI client and xAPI Model use a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface). Objects are [immutable](https://en.wikipedia.org/wiki/Immutable_object). + ## xAPI Java Client -### Getting a state +The xAPI Java Client can be used by learning record providers (LRP) to communicate with learning record stores (LRS) or a systems which follows the LRS requirements of one or more of the xAPI resources. +### Getting started +To use the xAPI Model include the appropriate XML in the `dependencies` section of your `pom.xml`, as shown in the following example: +```xml + + 4.0.0 + getting-started + + + + + dev.learning.xapi + xapi-client + 1.0.3 + + + +``` + +### State Resource + +The xAPI Client allows applications to store, change, fetch, or delete [state documents](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#23-state-resource). + +#### Getting a state + +Example: ```java -client.getState(r -> r.activityId("https://example.com/activity/1") +final var request = client.getState(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") .stateId("bookmark"), String.class) - + + .block(); +``` + +#### Posting a state + +Example: + +```java +client.postState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!")) + .block(); ``` +#### Putting a state + +Example: + +```java +client.putState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark") + + .state("Hello World!")) + + .block(); +``` + +#### Deleting a state + +Example: + +```java +client.deleteState(r -> r.activityId("https://example.com/activity/1") + + .agent(a -> a.name("A N Other").mbox("another@example.com")) + + .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") + + .stateId("bookmark")) + + .block(); +``` + + ## xAPI Java Model -The xAPI Model has a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface). Objects are [immutable](https://en.wikipedia.org/wiki/Immutable_object). +The xAPI model can be used by clients that send xAPI data or by servers that receive xAPI data. ### Getting started @@ -39,7 +121,7 @@ To use the xAPI Model include the appropriate XML in the `dependencies` section dev.learning.xapi xapi-model - 1.0.1 + 1.0.3 From 67cfe6f49a3cab5eb86bf1dce620c91ce71a1432 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 20:15:33 +0000 Subject: [PATCH 68/74] t --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bd947982..91727e15 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ xAPI Java helps you to create applications that send or receive xAPI [Statements](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#statements) or [Documents](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#10-documents). -There are two projects in this [Monorepo](https://en.wikipedia.org/wiki/Monorepo), The xAPI Java Client and the xAPI Java Model. +There are two projects in this [Monorepo](https://en.wikipedia.org/wiki/Monorepo), The xAPI Client and the xAPI Model. Both the xAPI client and xAPI Model use a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface). Objects are [immutable](https://en.wikipedia.org/wiki/Immutable_object). @@ -12,7 +12,7 @@ The xAPI Java Client can be used by learning record providers (LRP) to communica ### Getting started -To use the xAPI Model include the appropriate XML in the `dependencies` section of your `pom.xml`, as shown in the following example: +To use the xAPI Client include the appropriate XML in the `dependencies` section of your `pom.xml`, as shown in the following example: ```xml From 948e2d22082a720c1ffaadd9efcaa6152adb6fba Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 20:16:15 +0000 Subject: [PATCH 69/74] d --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 91727e15..a5381d1a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ xAPI Java helps you to create applications that send or receive xAPI [Statements](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#statements) or [Documents](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#10-documents). -There are two projects in this [Monorepo](https://en.wikipedia.org/wiki/Monorepo), The xAPI Client and the xAPI Model. +There are two projects in this [Monorepo](https://en.wikipedia.org/wiki/Monorepo), xAPI Client and xAPI Model. Both the xAPI client and xAPI Model use a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface). Objects are [immutable](https://en.wikipedia.org/wiki/Immutable_object). From 82555df1ad4a5e7b7d501d053070596b3beda476 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Thu, 9 Feb 2023 20:17:00 +0000 Subject: [PATCH 70/74] d --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5381d1a..27fc54da 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Both the xAPI client and xAPI Model use a [fluent interface](https://en.wikipedi ## xAPI Java Client -The xAPI Java Client can be used by learning record providers (LRP) to communicate with learning record stores (LRS) or a systems which follows the LRS requirements of one or more of the xAPI resources. +The xAPI Java Client can be used by learning record providers (LRP) to communicate with learning record stores (LRS) or a system which follows the LRS requirements of one or more of the xAPI resources. ### Getting started From 64a47e408f7c0885feb78715a4a7e60e8377bac3 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 10 Feb 2023 16:07:34 +0000 Subject: [PATCH 71/74] fix broken tests --- .../learning/xapi/client/XapiClientTests.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index f554a388..1debc04d 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -74,23 +74,6 @@ void whenGettingASingleStateThenMethodIsGet() throws InterruptedException { } - @Test - void d() throws InterruptedException { - - - final ResponseEntity request = - client.getState(r -> r.activityId("https://example.com/activity/1") - - .agent(a -> a.name("A N Other").mbox("another@example.com")) - - .registration("67828e3a-d116-4e18-8af3-2d2c59e27be6") - - .stateId("bookmark"), String.class).block(); - - final String state = request.getBody(); - - - } @Test void whenGettingASingleStateThenPathIsExpected() throws InterruptedException { From 689e029ec46864fe051369f6033a51f49a5db7a6 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 10 Feb 2023 16:16:37 +0000 Subject: [PATCH 72/74] tip --- .../dev/learning/xapi/client/DeleteStateRequest.java | 10 ++++++++++ .../dev/learning/xapi/client/DeleteStatesRequest.java | 10 ++++++++++ .../dev/learning/xapi/client/GetStatesRequest.java | 10 ++++++++++ .../dev/learning/xapi/client/PostStateRequest.java | 10 ++++++++++ .../java/dev/learning/xapi/client/PutStateRequest.java | 10 ++++++++++ .../main/java/dev/learning/xapi/client/XapiClient.java | 4 ---- 6 files changed, 50 insertions(+), 4 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index 80a61084..0f89fcf9 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -24,4 +24,14 @@ protected HttpMethod getMethod() { return HttpMethod.DELETE; } + /** + * Builder for DeleteStateRequest. + */ + public abstract static class Builder> + extends StateRequest.Builder { + + // This static class extends the lombok builder. + + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index 4a18e5a7..34fbefed 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -24,4 +24,14 @@ protected HttpMethod getMethod() { return HttpMethod.DELETE; } + /** + * Builder for DeleteStatesRequest. + */ + public abstract static class Builder> + extends StatesRequest.Builder { + + // This static class extends the lombok builder. + + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index 4cb1aa82..a3163192 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -43,4 +43,14 @@ protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) } + /** + * Builder for DeleteStateRequest. + */ + public abstract static class Builder> + extends StatesRequest.Builder { + + // This static class extends the lombok builder. + + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index f0d503ab..81f04638 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -41,4 +41,14 @@ protected HttpMethod getMethod() { return HttpMethod.POST; } + /** + * Builder for PostStateRequest. + */ + public abstract static class Builder> + extends StateRequest.Builder { + + // This static class extends the lombok builder. + + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index 2fb9ab82..db8c08a7 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -38,4 +38,14 @@ protected HttpMethod getMethod() { return HttpMethod.PUT; } + /** + * Builder for PutStateRequest. + */ + public abstract static class Builder> + extends StateRequest.Builder { + + // This static class extends the lombok builder. + + } + } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 0cfb5a92..1ca66587 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -4,7 +4,6 @@ package dev.learning.xapi.client; -import dev.learning.xapi.model.Agent; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -84,9 +83,6 @@ public Mono> getState(GetStateRequest request, Class bo public Mono> getState(Consumer> request, Class bodyType) { - - final Agent.Builder builder2 = Agent.builder(); - final GetStateRequest.Builder builder = GetStateRequest.builder(); request.accept(builder); From 0c779157f935e36a75e5600aeb9c455b7430c555 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 10 Feb 2023 16:31:54 +0000 Subject: [PATCH 73/74] pop --- .../java/dev/learning/xapi/client/StateRequest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index 94669f4f..f08df53d 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -34,4 +34,14 @@ protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) } + /** + * Builder for StateRequest. + */ + public abstract static class Builder> + extends StatesRequest.Builder { + + // This static class extends the lombok builder. + + } + } From 0cd08db5dd5c4d92dd3e8c416b6310664356289b Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 10 Feb 2023 16:59:53 +0000 Subject: [PATCH 74/74] tip --- README.md | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 27fc54da..2a20a3e9 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ final var request = client.getState(r -> r.activityId("https://example.com/activ .stateId("bookmark"), String.class) .block(); + +final String state = request.getBody(); ``` #### Posting a state @@ -144,21 +146,6 @@ final Statement statement = Statement.builder() .build(); ``` -```java -Agent agent = new Agent(); -agent.setMbox("mailto:info@tincanapi.com"); - -Verb verb = new Verb("http://adlnet.gov/expapi/verbs/attempted"); - -Activity activity = new Activity("http://rusticisoftware.github.com/TinCanJava"); - -Statement st = new Statement(); -st.setActor(agent); -st.setVerb(verb); -st.setObject(activity); - -``` - ### Deserializing Statements The Jackson ObjectMapper can be used to deserialize statements into Java objects. @@ -211,7 +198,7 @@ final String json = objectMapper.writeValueAsString(statement); ``` -### Creating a new statment using an existing statement as template +### Creating a new statement using an existing statement as template Example: