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