From 9db707e026d8af12c9fcb6e38d3375faf454b5e7 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Thu, 5 Sep 2024 22:55:57 +0200 Subject: [PATCH 01/15] feat: handle multiple ResponseInfo obj in Query response --- .../lyo/client/query/OslcQueryResult.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index 5654c10c7..52416a9c7 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -18,6 +18,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import javax.xml.datatype.DatatypeConfigurationException; @@ -124,12 +125,30 @@ private synchronized void initializeRdf() { Property responseInfo = rdfModel.createProperty(OslcConstants.OSLC_CORE_NAMESPACE, "ResponseInfo"); ResIterator iter = rdfModel.listResourcesWithProperty(rdfType, responseInfo); - //There should only be one - take the first - infoResource = null; + //The main ResposeInfo shall have the query URI or a page URI + List responseInfos = iter.toList(); + + infoResource = null; + if (responseInfos.size() == 1) { + infoResource = responseInfos.get(0); + } else if (responseInfos.size() > 1) { + List infos_sameURI = responseInfos.stream().filter(ri -> ri.getURI().equals(query.getQueryUrl())).toList(); + if (infos_sameURI.size() == 1) { + infoResource = infos_sameURI.get(0); + } else if (infos_sameURI.size() > 1) { + throw new IllegalStateException("Multiple ResponseInfo objects found with the same URI"); + } else { + // TODO: also check for oslc:nextPage before giving up + throw new IllegalStateException("Multiple ResponseInfo objects found; neither matches the Query URI"); + } + } + while (iter.hasNext()) { infoResource = iter.next(); break; } + + membersResource = rdfModel.getResource(query.getCapabilityUrl()); } } From 596f6fd33cd5b1976b0a992aee6ca0257207055c Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Sat, 7 Sep 2024 14:05:39 +0200 Subject: [PATCH 02/15] typo --- .../main/java/org/eclipse/lyo/client/query/OslcQueryResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index 52416a9c7..49488d676 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -125,7 +125,7 @@ private synchronized void initializeRdf() { Property responseInfo = rdfModel.createProperty(OslcConstants.OSLC_CORE_NAMESPACE, "ResponseInfo"); ResIterator iter = rdfModel.listResourcesWithProperty(rdfType, responseInfo); - //The main ResposeInfo shall have the query URI or a page URI + //The main ResponseInfo shall have the query URI or a page URI List responseInfos = iter.toList(); infoResource = null; From 1928470e4387593f18e2e512788d253ba5238847 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Tue, 1 Oct 2024 22:17:57 +0200 Subject: [PATCH 03/15] WIP --- .../lyo/client/{test => }/OslcClientTest.java | 4 +- .../{test => query}/OslcQueryResultTest.java | 17 +- .../src/test/resources/multiResponseQuery.rdf | 1397 +++++++++++++++++ 3 files changed, 1411 insertions(+), 7 deletions(-) rename client/oslc-client/src/test/java/org/eclipse/lyo/client/{test => }/OslcClientTest.java (95%) rename client/oslc-client/src/test/java/org/eclipse/lyo/client/{test => query}/OslcQueryResultTest.java (87%) create mode 100644 client/oslc-client/src/test/resources/multiResponseQuery.rdf diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/test/OslcClientTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java similarity index 95% rename from client/oslc-client/src/test/java/org/eclipse/lyo/client/test/OslcClientTest.java rename to client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java index 25729d7a4..66fe6fe26 100644 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/test/OslcClientTest.java +++ b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java @@ -11,7 +11,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.lyo.client.test; +package org.eclipse.lyo.client; import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; @@ -22,8 +22,6 @@ import javax.xml.namespace.QName; -import org.eclipse.lyo.client.OSLCConstants; -import org.eclipse.lyo.client.OslcClient; import org.eclipse.lyo.oslc4j.core.model.ServiceProvider; import org.junit.jupiter.api.Test; diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/test/OslcQueryResultTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java similarity index 87% rename from client/oslc-client/src/test/java/org/eclipse/lyo/client/test/OslcQueryResultTest.java rename to client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java index 3add622b6..a11e4fc4c 100644 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/test/OslcQueryResultTest.java +++ b/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java @@ -11,7 +11,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.lyo.client.test; +package org.eclipse.lyo.client.query; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; @@ -19,9 +19,6 @@ import java.io.InputStream; import org.eclipse.lyo.client.OslcClient; -import org.eclipse.lyo.client.query.OslcQuery; -import org.eclipse.lyo.client.query.OslcQueryParameters; -import org.eclipse.lyo.client.query.OslcQueryResult; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; @@ -105,6 +102,18 @@ public void testAnyMember() { assertEquals(5, result.getMembersUrls().length); } + @Test + public void testMultiResponseInfos() { +// System.setProperty(OslcQueryResult.SELECT_ANY_MEMBER, "true"); + Response mockedResponse = mockClientResponse("/multiResponseQuery.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setSelect("dcterms:title"); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(5, result.getMembersUrls().length); + } + private Response mockClientResponse(String file) { final InputStream is = OslcQueryResultTest.class.getResourceAsStream(file); Response mockedResponse = Mockito.mock(Response.class); diff --git a/client/oslc-client/src/test/resources/multiResponseQuery.rdf b/client/oslc-client/src/test/resources/multiResponseQuery.rdf new file mode 100644 index 000000000..28de9614d --- /dev/null +++ b/client/oslc-client/src/test/resources/multiResponseQuery.rdf @@ -0,0 +1,1397 @@ + + + + + + + 126285: Program + + + + + + + DP-479 + + + 2021-09-16T18:32:37.865Z + + + 2021-09-16T18:32:38.238Z + + + Image elements must provide a description in the 'alt' attribute for consumption by screen readers. + + + false + 1535 + + + false + + 1535 + + + + false + + + + + Implement accessibility in Pet Store application (updated) + _2nC4UBNvEeutmoeSPr3-Ag + + + + + false + false + false + + false + false + + + Task + New + + Task 1535 + + + + + Defect + false + + + 1115 + + + false + + + + 2021-04-07T10:38:21.136Z + + _2nC4UBNvEeutmoeSPr3-Ag + 2021-04-07T10:38:21.155Z + This is a System Change Request (A Defect) + + + + + false + New + Defect 1115 + + + + + + + + + + false + 1115 + + + false + false + false + false + + + + + + + + + 1044: PI Objective (Team) + + + Subscribed By + 1 + + + + + + + + DP-471 + + + + + + + + + Story + false + + false + 2020-10-21T09:38:25.551Z + + + false + 1046 + New + 2020-10-21T10:00:12.918Z + + Story + + Story 1046 + + false + + + false + + + + + + false + + 1046 + + false + false + + false + + 0 + + + + + + + _2nC4UBNvEeutmoeSPr3-Ag + + + + + + + + + + + + + + + + Accessibility verification using a screen reader + + + 2021-09-16T18:26:47.443Z + + + + + + + + false + false + + Image elements must provide a description in the 'alt' attribute for consumption by screen readers. + false + _2nC4UBNvEeutmoeSPr3-Ag + + + false + + + + 1531 + + 1531 + false + + New + + + + + Task + Task 1531 + false + 2021-09-16T18:26:48.129Z + + Implement accessibility in Pet Store application (updated) + false + + false + + + + + + + + + PI Objective (Program) + New + + + false + + + PI Objective 1042 + false + + + + + + + false + + + false + + + + + + PI Objective + + 2020-10-21T09:39:42.663Z + false + + 0 + + false + + 1042 + 1042 + + + _2nC4UBNvEeutmoeSPr3-Ag + + + + false + false + + 2020-10-21T09:32:48.097Z + + + + + + + + + Story 1050 + 1050 + false + 2020-12-14T11:45:52.188Z + + + + + + false + + + false + + + false + + + + 0 + 2020-12-14T11:53:03.066Z + _2nC4UBNvEeutmoeSPr3-Ag + + New + + + + + + + + Story + + + false + + false + + false + + + false + 1050 + + false + + + This is my story + + + + + + + configuring Essential SAFe for additional post-project initialization instructions + + + + + + + 1044: PI Objective (Team) + + + + + + + Accessibility verification using a screen reader + + + + + + + + + + + + + + + + + + + + + + + + + Subscribed By + 1 + + + + + + + + Accessibility verification using a screen reader + + + Subscribed By + 1 + + + + Subscribed By + 1 + + + + Defect + 2021-09-16T18:32:39.076Z + + Defect 1536 + + + + + + false + false + + + + + false + + false + + false + + + _2nC4UBNvEeutmoeSPr3-Ag + + + New + Error logging in + + 1536 + + 1536 + + + false + An error occurred when I tried to log in with a user ID that contained the '@' symbol. + + false + + + + + + 2021-09-16T18:32:39.067Z + false + + + + + + + DP-528 + + + + + + + DP-457 + + + 2021-04-08T13:11:56.081Z + false + + + + + + + + _2nC4UBNvEeutmoeSPr3-Ag + + + Task + + + + false + 1116 + + 1116 + New + + + + + + false + false + false + false + + + + + + 2021-04-07T10:40:39.882Z + + Task 1116 + false + false + + + need to create a ChangeRequest from Polarion + + + + + false + + + false + false + Defect 1532 + + + + + + + + + _2nC4UBNvEeutmoeSPr3-Ag + New + false + + + Defect + + + + 1532 + + 2021-09-16T18:26:49.032Z + false + + + Error logging in + false + + + + false + + 2021-09-16T18:26:49.021Z + false + An error occurred when I tried to log in with a user ID that contained the '@' symbol. + + + 1532 + + + + + + + + 126288: Non-Functional Requirement + + + + + + + DP-471 + + + false + false + + false + + + + + 2020-10-21T09:41:53.360Z + For <customers> who <do something> the <solution> is a <something - the "how"> that <provides this value> Unlike <competitor, current solution, or non-existing solution> our solution <does something better - the "why">



Outcomes hypothesis:

*

*



Leading indicators:

* (early innovation accounting measures)

*



NFRs:

*

*

+ _2nC4UBNvEeutmoeSPr3-Ag + + + + + + 1047 + + + + + 2020-10-21T09:41:27.851Z + + Draft + false + 1047 + 0 + + + 0 + Program Epic 1047 + + 0 + + + + + + Program Epic + false + + + + + false + 0.0 + false + Program Epic + + + + false + + + +
+ + + + + + 1045: Feature + + + + + + + Global Verifcation Test + + + Subscribed By + 1 + + + + false + false + + + false + + 1051 + Task 1051 + + + New + Test task demo for Erik + false + + 2021-04-07T10:55:47.342Z + + false + + Task + + _2nC4UBNvEeutmoeSPr3-Ag + + + + + false + + + + + false + 1051 + + + 2021-01-22T15:14:53.538Z + + + + + + + false + + + + + Subscribed By + 1 + + + + + + + + Accessibility verification using a screen reader + + + Subscribed By + 1 + + + + Subscribed By + 1 + + + + + + + + Global Verifcation Test + + + + + + + 126286: Team Non-Functional Requirement + + + + + + + DP-529 + + + + Implement accessibility in Pet Store application (updated) + 2310 + + false + false + + + false + + false + + + Task + + + false + + + Task 2310 + + false + + 2310 + 2023-07-16T19:19:27.418Z + _2nC4UBNvEeutmoeSPr3-Ag + + false + + + + + false + New + + 2023-07-16T19:19:26.374Z + + + + Image elements must provide a description in the 'alt' attribute for consumption by screen readers. + + + + + + + + + + 1046: Story + + + + + + false + + + 1537 + + + + false + + + 1537 + + false + false + + 2021-09-16T18:32:56.025Z + Image elements must provide a description in the 'alt' attribute for consumption by screen readers. + + Task + + + + 2021-09-16T18:32:55.653Z + + + false + false + + Task 1537 + false + + + Implement accessibility in Pet Store application (updated) + _2nC4UBNvEeutmoeSPr3-Ag + + + New + + + false + + + + + Task + 1533 + + _2nC4UBNvEeutmoeSPr3-Ag + New + Implement accessibility in Pet Store application (updated) + + false + Task 1533 + false + + + + 2021-09-16T18:31:15.255Z + + 1533 + + + + + false + + + + + false + false + + false + false + + Image elements must provide a description in the 'alt' attribute for consumption by screen readers. + + + false + 2021-09-16T18:31:15.641Z + + + + + + + + Subscribed By + 1 + + + + + + + + 1042: PI Objective (Program) + + + + + + + DP-477 + + + Subscribed By + 1 + + + + Subscribed By + 1 + + + + Subscribed By + 1 + + + + + + + + DP-527 + + + + + false + + + + false + 1044 + + + + + + + PI Objective 1044 + false + 1044 + + + false + + + + New + false + + + + + PI Objective (Team) + + false + false + + PI Objective + false + + 0 + + + + 2020-10-21T09:40:03.820Z + 2020-10-21T09:33:26.547Z + _2nC4UBNvEeutmoeSPr3-Ag + + + + + + Subscribed By + 1 + + + + + Work Items + 537 + + + + Subscribed By + 1 + + + + + + _2nC4UBNvEeutmoeSPr3-Ag + + + false + + false + + + + 1040 + + Post-Project Initialization + + false + + + 2020-10-21T07:35:20.513Z + + New + false + + + 2020-10-21T07:35:20.370Z + Task 1040 + + See, configuring Essential SAFe for additional post-project initialization instructions.



+ false + + false + Task + + + + false + false + + + + 1040 + + +
+ + Subscribed By + 1 + + + + + + + + 1045: Feature + + + + + + + 126287: Team User Requirement + + + + + + + Accessibility verification using a screen reader + + + + + false + + + + + false + 2021-04-08T13:14:06.622Z + 1118 + + + 1118 + + + Feature 1118 + + false + + + 0 + 0.0 + Draft + false + + + + + false + + + 0 + false + + + + false + + + + + + + + + + + 2021-11-08T08:35:53.632Z + + + A Change Request to trace to many development tasks in Polarion + 0 + + + + + + + false + + Feature + + _2nC4UBNvEeutmoeSPr3-Ag + false + + + + + + + + DP-525 + + + + Defect 1538 + + false + false + + + false + 1538 + + false + _2nC4UBNvEeutmoeSPr3-Ag + + + New + + + + + false + + + false + + + + false + An error occurred when I tried to log in with a user ID that contained the '@' symbol. + + 1538 + + + + + + false + Defect + + 2021-09-16T18:32:56.877Z + Error logging in + 2021-09-16T18:32:56.868Z + + + + + + Subscribed By + 1 + + + + + + + + 126289: User Requirement + + + + + + + DP-479 + + + false + false + + + + + 1534 + + + Error logging in + _2nC4UBNvEeutmoeSPr3-Ag + + New + + false + Defect + false + + 2021-09-16T18:31:16.492Z + + + + + + + false + 2021-09-16T18:31:16.501Z + + + + Defect 1534 + + false + 1534 + + + + + + + An error occurred when I tried to log in with a user ID that contained the '@' symbol. + false + + false + + + + + + + 1046: Story + + + Subscribed By + 1 + + + + + + + + DP-440 + + + + + + + false + + + + + 1045 + + + + + + + + + _2nC4UBNvEeutmoeSPr3-Ag + false + + + + + + false + + false + false + + 2020-10-21T09:37:00.992Z + + false + + + 1045 + 2020-12-11T15:19:32.749Z + Draft + + + + Feature + 0.0 + 0 + + Feature + + + + 0 + + + + Feature 1045 + 0 + + false + + + + + + + + false + false + + + + + + + Global Verifcation Test + + + Subscribed By + 1 + + + + + + + + 1045: Feature + + + + + + + Global Verifcation Test + + + + + + + 1047: Program Epic + + + Subscribed By + 1 + + + + + + + + 1042: PI Objective (Program) + + + Subscribed By + 1 + + + + + + + + DP-528 + +
From 8317ffc2ee343ef07bbd3a4169a0a1a910c5c65b Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Tue, 1 Oct 2024 23:07:14 +0200 Subject: [PATCH 04/15] fix: update the query pick code & test --- .../lyo/client/query/OslcQueryResult.java | 72 ++++++++++++++----- .../eclipse/lyo/client/OslcClientTest.java | 3 - .../lyo/client/query/OslcQueryResultTest.java | 7 +- 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index 49488d676..a51dacd5e 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -129,31 +129,65 @@ private synchronized void initializeRdf() { List responseInfos = iter.toList(); infoResource = null; - if (responseInfos.size() == 1) { - infoResource = responseInfos.get(0); - } else if (responseInfos.size() > 1) { - List infos_sameURI = responseInfos.stream().filter(ri -> ri.getURI().equals(query.getQueryUrl())).toList(); - if (infos_sameURI.size() == 1) { - infoResource = infos_sameURI.get(0); - } else if (infos_sameURI.size() > 1) { - throw new IllegalStateException("Multiple ResponseInfo objects found with the same URI"); - } else { - // TODO: also check for oslc:nextPage before giving up - throw new IllegalStateException("Multiple ResponseInfo objects found; neither matches the Query URI"); - } + infoResource = tryFindOnlyResponseInfo(responseInfos); + if(infoResource == null && responseInfos.size() > 1) { + infoResource = tryFindExactResponseInfoUri(responseInfos); + } + if(infoResource == null && responseInfos.size() > 1) { + infoResource = tryFindPrefixedResponseInfoUri(responseInfos); + } + if(infoResource == null) { + // TODO: also check for oslc:nextPage before giving up + throw new IllegalStateException("Multiple ResponseInfo objects found; neither matches the Query URI"); } - - while (iter.hasNext()) { - infoResource = iter.next(); - break; - } - membersResource = rdfModel.getResource(query.getCapabilityUrl()); } } - String getNextPageUrl() { + /** + * Extracts a ResourceInfo resource if one and only one has the same prefix as the query URI. + * @param responseInfos from OSLC Query results + * @return a ResourceInfo resource if one satisfies the conditions; null otherwise + */ + private Resource tryFindPrefixedResponseInfoUri(List responseInfos) { + List filteredObjects = responseInfos.stream().filter(ri -> ri.getURI().startsWith(query.getQueryUrl())).toList(); + if (filteredObjects.size() == 1) { + return filteredObjects.get(0); + } else if (filteredObjects.size() > 1) { + throw new IllegalStateException("Multiple ResponseInfo objects found starting with the same Query URI"); + } + return null; + } + + /** + * Extracts a ResourceInfo resource if one and only one has exactly the same URI as the query URI. + * @param responseInfos from OSLC Query results + * @return a ResourceInfo resource if one satisfies the conditions; null otherwise + */ + private Resource tryFindExactResponseInfoUri(List responseInfos) { + List filteredObjects = responseInfos.stream().filter(ri -> ri.getURI().equals(query.getQueryUrl())).toList(); + if (filteredObjects.size() == 1) { + return filteredObjects.get(0); + } else if (filteredObjects.size() > 1) { + throw new IllegalStateException("Multiple ResponseInfo objects found with the same URI"); + } + return null; + } + + /** + * Extracts a ResourceInfo resource if one and only one exists in the results. + * @param responseInfos from OSLC Query results + * @return a ResourceInfo resource if one satisfies the conditions; null otherwise + */ + private Resource tryFindOnlyResponseInfo(List responseInfos) { + if (responseInfos.size() == 1) { + return responseInfos.get(0); + } + return null; + } + + String getNextPageUrl() { initializeRdf(); if ((nextPageUrl == null || nextPageUrl.isEmpty()) && infoResource != null) { Property predicate = rdfModel.getProperty(OslcConstants.OSLC_CORE_NAMESPACE, "nextPage"); diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java index 66fe6fe26..3643f2315 100644 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java +++ b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java @@ -42,9 +42,6 @@ public void postInvalidOlscResource() throws IOException, URISyntaxException { request.getExtendedProperties().put(new QName("http://example.com/ns#", "test"), "test"); Response response = client.createResource("http://open-services.net/.well-known/resource-that-should-not-exist-whose-status-code-should-not-be-200", request, OSLCConstants.CT_RDF); assertThat(response.getStatusInfo().getFamily() != Family.SUCCESSFUL); -// assertThrows(ClientErrorException.class, () -> { -// -// }); }); } diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java index a11e4fc4c..4f1dfc44f 100644 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java +++ b/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java @@ -104,14 +104,15 @@ public void testAnyMember() { @Test public void testMultiResponseInfos() { -// System.setProperty(OslcQueryResult.SELECT_ANY_MEMBER, "true"); + // seems to work with both +// System.setProperty(OslcQueryResult.SELECT_ANY_MEMBER, "false"); Response mockedResponse = mockClientResponse("/multiResponseQuery.rdf"); OslcQueryParameters params = new OslcQueryParameters(); params.setSelect("dcterms:title"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); + OslcQuery query = new OslcQuery(new OslcClient(), "https://nordic.clm.ibmcloud.com/ccm/oslc/contexts/_2nC4UBNvEeutmoeSPr3-Ag/workitems"); OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(5, result.getMembersUrls().length); + assertEquals(20, result.getMembersUrls().length); } private Response mockClientResponse(String file) { From dfb4af61e4180c6dd769e56b4f154c0c7650cfea Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Tue, 1 Oct 2024 23:29:43 +0200 Subject: [PATCH 05/15] docs: update javadoc --- .../org/eclipse/lyo/client/query/OslcQueryResult.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index a51dacd5e..f899d82b4 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -138,7 +138,7 @@ private synchronized void initializeRdf() { } if(infoResource == null) { // TODO: also check for oslc:nextPage before giving up - throw new IllegalStateException("Multiple ResponseInfo objects found; neither matches the Query URI"); + throw new IllegalStateException("Failed to find an appropriate ResponseInfo object"); } membersResource = rdfModel.getResource(query.getCapabilityUrl()); @@ -148,7 +148,8 @@ private synchronized void initializeRdf() { /** * Extracts a ResourceInfo resource if one and only one has the same prefix as the query URI. * @param responseInfos from OSLC Query results - * @return a ResourceInfo resource if one satisfies the conditions; null otherwise + * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy + * @throws IllegalStateException if multiple resources satisfy the same condition */ private Resource tryFindPrefixedResponseInfoUri(List responseInfos) { List filteredObjects = responseInfos.stream().filter(ri -> ri.getURI().startsWith(query.getQueryUrl())).toList(); @@ -163,7 +164,8 @@ private Resource tryFindPrefixedResponseInfoUri(List responseInfos) { /** * Extracts a ResourceInfo resource if one and only one has exactly the same URI as the query URI. * @param responseInfos from OSLC Query results - * @return a ResourceInfo resource if one satisfies the conditions; null otherwise + * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy + * @throws IllegalStateException if multiple resources satisfy the same condition */ private Resource tryFindExactResponseInfoUri(List responseInfos) { List filteredObjects = responseInfos.stream().filter(ri -> ri.getURI().equals(query.getQueryUrl())).toList(); @@ -178,7 +180,7 @@ private Resource tryFindExactResponseInfoUri(List responseInfos) { /** * Extracts a ResourceInfo resource if one and only one exists in the results. * @param responseInfos from OSLC Query results - * @return a ResourceInfo resource if one satisfies the conditions; null otherwise + * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy */ private Resource tryFindOnlyResponseInfo(List responseInfos) { if (responseInfos.size() == 1) { From 319881779c4b75be245e830742c7c0df50fd795f Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Sat, 5 Oct 2024 12:32:19 +0200 Subject: [PATCH 06/15] docs: update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac6c43f73..59f532bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ ### Fixed +- Client now picks the correct ResponseInfo object when an OSLC Query response contains multiple ResponseInfo objects. + ## [6.0.0] ### Security From b8d956c8c392f0cf6958c31ffce383ca906a6595 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Mon, 21 Oct 2024 22:30:29 +0200 Subject: [PATCH 07/15] chore: reformat --- .../eclipse/lyo/client/OslcClientTest.java | 54 ++++++------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java index 8770ba752..ac7e8b35e 100644 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java +++ b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java @@ -13,41 +13,26 @@ */ package org.eclipse.lyo.client; -import static java.time.Duration.ofSeconds; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertTimeout; - -import java.io.IOException; -import java.net.URISyntaxException; - -import javax.xml.namespace.QName; - +import jakarta.ws.rs.client.Invocation.Builder; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status.Family; +import org.apache.http.HttpHeaders; import org.eclipse.lyo.oslc4j.core.model.ServiceProvider; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; -import static org.junit.Assert.assertNull; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTimeout; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - +import javax.xml.namespace.QName; import java.io.IOException; import java.net.URISyntaxException; import java.util.Map; -import javax.xml.namespace.QName; - -import org.apache.http.HttpHeaders; -import org.eclipse.lyo.oslc4j.core.model.ServiceProvider; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import jakarta.ws.rs.client.Invocation.Builder; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status.Family; +import static java.time.Duration.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; public class OslcClientTest { /** @@ -61,9 +46,7 @@ public void postInvalidOlscResource() throws IOException, URISyntaxException { final OslcClient client = new OslcClient(); final ServiceProvider request = new ServiceProvider(); request.getExtendedProperties().put(new QName("http://example.com/ns#", "test"), "test"); - Response response = client.createResource( - "http://open-services.net/.well-known/resource-that-should-not-exist-whose-status-code-should-not-be-200", - request, OSLCConstants.CT_RDF); + Response response = client.createResource("http://open-services.net/.well-known/resource-that-should-not-exist-whose-status-code-should-not-be-200", request, OSLCConstants.CT_RDF); assertThat(response.getStatusInfo().getFamily() != Family.SUCCESSFUL); // assertThrows(ClientErrorException.class, () -> { // @@ -94,13 +77,11 @@ public void testGetResource() { clearInvocations(client); client.getResource("test.url", "application/rdf+xml"); - verify(client).doRequest("GET", "test.url", null, null, null, "application/rdf+xml", "application/rdf+xml", - null); + verify(client).doRequest("GET", "test.url", null, null, null, "application/rdf+xml", "application/rdf+xml", null); clearInvocations(client); client.getResource("test.url", Map.of("a", "b"), "application/rdf+xml", "oslc.context"); - verify(client).doRequest("GET", "test.url", null, "oslc.context", null, "application/rdf+xml", - "application/rdf+xml", Map.of("a", "b")); + verify(client).doRequest("GET", "test.url", null, "oslc.context", null, "application/rdf+xml", "application/rdf+xml", Map.of("a", "b")); } @Test @@ -113,8 +94,7 @@ public void testPutResource() { clearInvocations(client); client.updateResource("test.url", "artifact", "application/json", "*/*", "ifmatch", "configContext"); - verify(client).doRequest("PUT", "test.url", "artifact", "configContext", "ifmatch", "application/json", "*/*", - null); + verify(client).doRequest("PUT", "test.url", "artifact", "configContext", "ifmatch", "application/json", "*/*", null); clearInvocations(client); From e7b07ad5fd7ceef52380e813e6e2f8aaec68a624 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Mon, 21 Oct 2024 22:32:40 +0200 Subject: [PATCH 08/15] chore: reformat again; enforce line len --- .../eclipse/lyo/client/OslcClientTest.java | 58 +++++++++++++------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java index ac7e8b35e..5a84d94d1 100644 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java +++ b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcClientTest.java @@ -37,16 +37,21 @@ public class OslcClientTest { /** * Tests that the RDF/XML MessageBodyWriter doesn't go into an infinite loop when - * given bad data on the client (Bug 417749). ClientRuntimeException no longer expected in Lyo 4.0. + * given bad data on the client (Bug 417749). ClientRuntimeException no longer expected in + * Lyo 4.0. */ -// @Disabled("Unit test actually POSTs data to example.com, which we shouldn't do as we don't own that domain.") +// @Disabled("Unit test actually POSTs data to example.com, which we shouldn't do as we don't +// own that domain.") @Test public void postInvalidOlscResource() throws IOException, URISyntaxException { assertTimeout(ofSeconds(10), () -> { final OslcClient client = new OslcClient(); final ServiceProvider request = new ServiceProvider(); - request.getExtendedProperties().put(new QName("http://example.com/ns#", "test"), "test"); - Response response = client.createResource("http://open-services.net/.well-known/resource-that-should-not-exist-whose-status-code-should-not-be-200", request, OSLCConstants.CT_RDF); + request.getExtendedProperties().put(new QName("http://example.com/ns#", "test"), + "test"); + Response response = client.createResource("http://open-services.net/" + + ".well-known/resource-that-should-not-exist-whose-status-code-should-not-be-200", + request, OSLCConstants.CT_RDF); assertThat(response.getStatusInfo().getFamily() != Family.SUCCESSFUL); // assertThrows(ClientErrorException.class, () -> { // @@ -71,69 +76,84 @@ public void connectionTest() { @Test public void testGetResource() { OslcClient client = mock(OslcClient.class, Mockito.CALLS_REAL_METHODS); - doReturn(null).when(client).doRequest(any(), any(), any(), any(), any(), any(), any(), any()); + doReturn(null).when(client).doRequest(any(), any(), any(), any(), any(), any(), any(), + any()); client.getResource("test.url"); - verify(client).doRequest("GET", "test.url", null, null, null, null, "application/rdf+xml", null); + verify(client).doRequest("GET", "test.url", null, null, null, null, "application/rdf+xml" + , null); clearInvocations(client); client.getResource("test.url", "application/rdf+xml"); - verify(client).doRequest("GET", "test.url", null, null, null, "application/rdf+xml", "application/rdf+xml", null); + verify(client).doRequest("GET", "test.url", null, null, null, "application/rdf+xml", + "application/rdf+xml", null); clearInvocations(client); client.getResource("test.url", Map.of("a", "b"), "application/rdf+xml", "oslc.context"); - verify(client).doRequest("GET", "test.url", null, "oslc.context", null, "application/rdf+xml", "application/rdf+xml", Map.of("a", "b")); + verify(client).doRequest("GET", "test.url", null, "oslc.context", null, "application/rdf" + + "+xml", "application/rdf+xml", Map.of("a", "b")); } @Test public void testPutResource() { OslcClient client = mock(OslcClient.class, Mockito.CALLS_REAL_METHODS); - doReturn(null).when(client).doRequest(any(), any(), any(), any(), any(), any(), any(), any()); + doReturn(null).when(client).doRequest(any(), any(), any(), any(), any(), any(), any(), + any()); client.updateResource("test.url", "artifact", "application/json"); - verify(client).doRequest("PUT", "test.url", "artifact", null, null, "application/json", "*/*", null); + verify(client).doRequest("PUT", "test.url", "artifact", null, null, "application/json", + "*/*", null); clearInvocations(client); - client.updateResource("test.url", "artifact", "application/json", "*/*", "ifmatch", "configContext"); - verify(client).doRequest("PUT", "test.url", "artifact", "configContext", "ifmatch", "application/json", "*/*", null); + client.updateResource("test.url", "artifact", "application/json", "*/*", "ifmatch", + "configContext"); + verify(client).doRequest("PUT", "test.url", "artifact", "configContext", "ifmatch", + "application/json", "*/*", null); clearInvocations(client); client.updateResource("test.url", "artifact", "application/json", "*/*", "ifmatch"); - verify(client).doRequest("PUT", "test.url", "artifact", null, "ifmatch", "application/json", "*/*", null); + verify(client).doRequest("PUT", "test.url", "artifact", null, "ifmatch", "application" + + "/json", "*/*", null); } @Test public void testDeleteResource() { OslcClient client = mock(OslcClient.class, Mockito.CALLS_REAL_METHODS); - doReturn(null).when(client).doRequest(any(), any(), any(), any(), any(), any(), any(), any()); + doReturn(null).when(client).doRequest(any(), any(), any(), any(), any(), any(), any(), + any()); client.deleteResource("test.url"); verify(client).doRequest("DELETE", "test.url", null, null, null, null, null, null); clearInvocations(client); client.deleteResource("test.url", "configContext"); - verify(client).doRequest("DELETE", "test.url", null, "configContext", null, null, null, null); + verify(client).doRequest("DELETE", "test.url", null, "configContext", null, null, null, + null); } @Test public void testCreateResource() { OslcClient client = mock(OslcClient.class, Mockito.CALLS_REAL_METHODS); - doReturn(null).when(client).doRequest(any(), any(), any(), any(), any(), any(), any(), any()); + doReturn(null).when(client).doRequest(any(), any(), any(), any(), any(), any(), any(), + any()); client.createResource("test.url", "artifact", "application/rdf+xml"); - verify(client).doRequest("POST", "test.url", "artifact", null, null, "application/rdf+xml", "*/*", null); + verify(client).doRequest("POST", "test.url", "artifact", null, null, "application/rdf+xml" + , "*/*", null); clearInvocations(client); client.createResource("test.url", "artifact", "application/rdf+xml", "*/*", "oslc.ctx"); - verify(client).doRequest("POST", "test.url", "artifact", "oslc.ctx", null, "application/rdf+xml", "*/*", null); + verify(client).doRequest("POST", "test.url", "artifact", "oslc.ctx", null, "application" + + "/rdf+xml", "*/*", null); } @Test public void testAddHeaders() { OslcClient client = new OslcClient(); Builder builder = mock(Builder.class); - Map headers = client.addHeaders(builder, Map.of("a", "b"), "ifmatch", "ctx"); + Map headers = client.addHeaders(builder, Map.of("a", "b"), "ifmatch", + "ctx"); assertEquals(4, headers.size()); assertEquals("b", headers.get("a")); From d2adc41b3a44dd7b440dd7801cb0c2acffa72bd3 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Mon, 21 Oct 2024 22:34:26 +0200 Subject: [PATCH 09/15] chore: reformat the rest --- .../lyo/client/query/OslcQueryResult.java | 402 +++++++++--------- .../lyo/client/OslcQueryResultTest.java | 149 +++---- 2 files changed, 284 insertions(+), 267 deletions(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index f899d82b4..c71096829 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -13,15 +13,7 @@ */ package org.eclipse.lyo.client.query; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.xml.datatype.DatatypeConfigurationException; - +import jakarta.ws.rs.core.Response; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Property; @@ -39,146 +31,165 @@ import org.eclipse.lyo.oslc4j.core.model.OslcConstants; import org.eclipse.lyo.oslc4j.provider.jena.JenaModelHelper; -import jakarta.ws.rs.core.Response; +import javax.xml.datatype.DatatypeConfigurationException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; /** - * The results of an OSLC query. If the query was paged, subsequent pages can be retrieved using the Iterator interface. - * + * The results of an OSLC query. If the query was paged, subsequent pages can be retrieved using + * the Iterator interface. + *

* This class is not currently thread safe. */ public class OslcQueryResult implements Iterator { - /** - * The default member property to look for in OSLC query results - * (rdfs:member). Can be changed using {@link #setMemberProperty(String)}. - */ - public final static Property DEFAULT_MEMBER_PROPERTY = RDFS.member; - - /** - * If system property {@value} is set to true, find any member in the - */ - public final static String SELECT_ANY_MEMBER = "org.eclipse.lyo.client.oslc.query.selectAnyMember"; - - /** - * Treat any resource in the members resource as a query result (except rdf:type). - * - * @see OslcQueryResult#SELECT_ANY_MEMBER - */ - private final class AnyMemberSelector extends SimpleSelector { - private AnyMemberSelector(Resource subject) { - super(subject, null, (RDFNode) null); - } - - public boolean selects(Statement s) { - String fqPredicateName = s.getPredicate().getNameSpace() + s.getPredicate().getLocalName(); - if (OSLCConstants.RDF_TYPE_PROP.equals(fqPredicateName)) { - return false; - } - - return s.getObject().isResource(); - } + /** + * The default member property to look for in OSLC query results + * (rdfs:member). Can be changed using {@link #setMemberProperty(String)}. + */ + public final static Property DEFAULT_MEMBER_PROPERTY = RDFS.member; + + /** + * If system property {@value} is set to true, find any member in the + */ + public final static String SELECT_ANY_MEMBER = "org.eclipse.lyo.client.oslc.query" + + ".selectAnyMember"; + + /** + * Treat any resource in the members resource as a query result (except rdf:type). + * + * @see OslcQueryResult#SELECT_ANY_MEMBER + */ + private final class AnyMemberSelector extends SimpleSelector { + private AnyMemberSelector(Resource subject) { + super(subject, null, (RDFNode) null); + } + + public boolean selects(Statement s) { + String fqPredicateName = + s.getPredicate().getNameSpace() + s.getPredicate().getLocalName(); + if (OSLCConstants.RDF_TYPE_PROP.equals(fqPredicateName)) { + return false; + } + + return s.getObject().isResource(); + } } - private final OslcQuery query; + private final OslcQuery query; - private final Response response; + private final Response response; - private final int pageNumber; + private final int pageNumber; - private Property memberProperty = DEFAULT_MEMBER_PROPERTY; + private Property memberProperty = DEFAULT_MEMBER_PROPERTY; - private Model rdfModel; + private Model rdfModel; - private Resource infoResource, membersResource; + private Resource infoResource, membersResource; - private String nextPageUrl = ""; + private String nextPageUrl = ""; - private boolean rdfInitialized = false; + private boolean rdfInitialized = false; - public OslcQueryResult(OslcQuery query, Response response) { - this.query = query; - this.response = response; + public OslcQueryResult(OslcQuery query, Response response) { + this.query = query; + this.response = response; - this.pageNumber = 1; + this.pageNumber = 1; - } + } - private OslcQueryResult(OslcQueryResult prev) { - this.query = new OslcQuery(prev); - this.response = this.query.getResponse(); - this.membersResource = prev.membersResource; - this.memberProperty = prev.memberProperty; + private OslcQueryResult(OslcQueryResult prev) { + this.query = new OslcQuery(prev); + this.response = this.query.getResponse(); + this.membersResource = prev.membersResource; + this.memberProperty = prev.memberProperty; - this.pageNumber = prev.pageNumber + 1; + this.pageNumber = prev.pageNumber + 1; - } + } - private synchronized void initializeRdf() { - if (!rdfInitialized) { - rdfInitialized = true; - rdfModel = ModelFactory.createDefaultModel(); - rdfModel.read(response.readEntity(InputStream.class), query.getCapabilityUrl()); + private synchronized void initializeRdf() { + if (!rdfInitialized) { + rdfInitialized = true; + rdfModel = ModelFactory.createDefaultModel(); + rdfModel.read(response.readEntity(InputStream.class), query.getCapabilityUrl()); - //Find a resource with rdf:type of oslc:ResourceInfo - Property rdfType = rdfModel.createProperty(OslcConstants.RDF_NAMESPACE, "type"); - Property responseInfo = rdfModel.createProperty(OslcConstants.OSLC_CORE_NAMESPACE, "ResponseInfo"); - ResIterator iter = rdfModel.listResourcesWithProperty(rdfType, responseInfo); + //Find a resource with rdf:type of oslc:ResourceInfo + Property rdfType = rdfModel.createProperty(OslcConstants.RDF_NAMESPACE, "type"); + Property responseInfo = rdfModel.createProperty(OslcConstants.OSLC_CORE_NAMESPACE, + "ResponseInfo"); + ResIterator iter = rdfModel.listResourcesWithProperty(rdfType, responseInfo); - //The main ResponseInfo shall have the query URI or a page URI + //The main ResponseInfo shall have the query URI or a page URI List responseInfos = iter.toList(); infoResource = null; infoResource = tryFindOnlyResponseInfo(responseInfos); - if(infoResource == null && responseInfos.size() > 1) { + if (infoResource == null && responseInfos.size() > 1) { infoResource = tryFindExactResponseInfoUri(responseInfos); } - if(infoResource == null && responseInfos.size() > 1) { + if (infoResource == null && responseInfos.size() > 1) { infoResource = tryFindPrefixedResponseInfoUri(responseInfos); } - if(infoResource == null) { + if (infoResource == null) { // TODO: also check for oslc:nextPage before giving up - throw new IllegalStateException("Failed to find an appropriate ResponseInfo object"); + throw new IllegalStateException("Failed to find an appropriate ResponseInfo " + + "object"); } - membersResource = rdfModel.getResource(query.getCapabilityUrl()); - } - } + membersResource = rdfModel.getResource(query.getCapabilityUrl()); + } + } /** * Extracts a ResourceInfo resource if one and only one has the same prefix as the query URI. + * * @param responseInfos from OSLC Query results * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy * @throws IllegalStateException if multiple resources satisfy the same condition */ private Resource tryFindPrefixedResponseInfoUri(List responseInfos) { - List filteredObjects = responseInfos.stream().filter(ri -> ri.getURI().startsWith(query.getQueryUrl())).toList(); + List filteredObjects = + responseInfos.stream().filter(ri -> ri.getURI().startsWith(query.getQueryUrl())).toList(); if (filteredObjects.size() == 1) { return filteredObjects.get(0); } else if (filteredObjects.size() > 1) { - throw new IllegalStateException("Multiple ResponseInfo objects found starting with the same Query URI"); + throw new IllegalStateException("Multiple ResponseInfo objects found starting with " + + "the same Query URI"); } return null; } /** - * Extracts a ResourceInfo resource if one and only one has exactly the same URI as the query URI. + * Extracts a ResourceInfo resource if one and only one has exactly the same URI as the query + * URI. + * * @param responseInfos from OSLC Query results * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy * @throws IllegalStateException if multiple resources satisfy the same condition */ private Resource tryFindExactResponseInfoUri(List responseInfos) { - List filteredObjects = responseInfos.stream().filter(ri -> ri.getURI().equals(query.getQueryUrl())).toList(); + List filteredObjects = + responseInfos.stream().filter(ri -> ri.getURI().equals(query.getQueryUrl())).toList(); if (filteredObjects.size() == 1) { return filteredObjects.get(0); } else if (filteredObjects.size() > 1) { - throw new IllegalStateException("Multiple ResponseInfo objects found with the same URI"); + throw new IllegalStateException("Multiple ResponseInfo objects found with the same " + + "URI"); } return null; } /** * Extracts a ResourceInfo resource if one and only one exists in the results. + * * @param responseInfos from OSLC Query results * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy */ @@ -190,115 +201,117 @@ private Resource tryFindOnlyResponseInfo(List responseInfos) { } String getNextPageUrl() { - initializeRdf(); - if ((nextPageUrl == null || nextPageUrl.isEmpty()) && infoResource != null) { - Property predicate = rdfModel.getProperty(OslcConstants.OSLC_CORE_NAMESPACE, "nextPage"); - Selector select = new SimpleSelector(infoResource, predicate, (RDFNode) null); - StmtIterator iter = rdfModel.listStatements(select); - if (iter.hasNext()) { - Statement nextPage = iter.next(); - nextPageUrl = nextPage.getResource().getURI(); - } else { - nextPageUrl = ""; - } - } - return nextPageUrl; - } - - /** - * @return whether there is another page of results after this - */ - public boolean hasNext() { - return (!"".equals(getNextPageUrl())); - } - - /** - * @return the next page of results - */ - public OslcQueryResult next() { - return new OslcQueryResult(this); - } - - /** - * @throws UnsupportedOperationException always - */ - public void remove() { - throw new UnsupportedOperationException(); - } - - public OslcQuery getQuery() { - return query; - } - - /** - * Returns the member property to find query result resources. - * - * @return the member property URI - * @see #setMemberProperty(String) - */ - public String getMemberProperty() { - return this.memberProperty.getURI(); - } - - /** - * Sets the predicate to use to find query result resources. If unset, - * defaults to {@code http://www.w3.org/2000/01/rdf-schema#member}. - * - * @param memberPredicate - * the RDF predicate for member resources from the provider's - * query shape - * @see Specifying the sahpe of a query - */ - public void setMemberProperty(String memberPredicate) { - this.memberProperty = ModelFactory.createDefaultModel().createProperty(memberPredicate); - } - - /** - * Get the raw Wink client response to a query. - * - * NOTE: Using this method and consuming the response will make other methods - * which examine the response unavailable (Examples: getMemberUrls(), next() and hasNext()). - * When this method is invoked, the consumer is responsible for OSLC page processing - * - * @return - */ - public Response getRawResponse() { - return response; - } - - private Selector getMemberSelector() { - if ("true".equalsIgnoreCase(System.getProperty(SELECT_ANY_MEMBER))) { - return new AnyMemberSelector(membersResource); - } - - return new SimpleSelector(membersResource, memberProperty, (RDFNode) null); - } - - /** - * Return the subject URLs of the query response. The URLs are the location of all artifacts - * which satisfy the query conditions. - * - * NOTE: Using this method consumes the query response and makes other methods - * which examine the response unavailable (Example: getRawResponse(). - * @return - */ - public String[] getMembersUrls() { - initializeRdf(); - ArrayList membersUrls = new ArrayList<>(); + initializeRdf(); + if ((nextPageUrl == null || nextPageUrl.isEmpty()) && infoResource != null) { + Property predicate = rdfModel.getProperty(OslcConstants.OSLC_CORE_NAMESPACE, + "nextPage"); + Selector select = new SimpleSelector(infoResource, predicate, (RDFNode) null); + StmtIterator iter = rdfModel.listStatements(select); + if (iter.hasNext()) { + Statement nextPage = iter.next(); + nextPageUrl = nextPage.getResource().getURI(); + } else { + nextPageUrl = ""; + } + } + return nextPageUrl; + } + + /** + * @return whether there is another page of results after this + */ + public boolean hasNext() { + return (!"".equals(getNextPageUrl())); + } + + /** + * @return the next page of results + */ + public OslcQueryResult next() { + return new OslcQueryResult(this); + } + + /** + * @throws UnsupportedOperationException always + */ + public void remove() { + throw new UnsupportedOperationException(); + } + + public OslcQuery getQuery() { + return query; + } + + /** + * Returns the member property to find query result resources. + * + * @return the member property URI + * @see #setMemberProperty(String) + */ + public String getMemberProperty() { + return this.memberProperty.getURI(); + } + + /** + * Sets the predicate to use to find query result resources. If unset, + * defaults to {@code http://www.w3.org/2000/01/rdf-schema#member}. + * + * @param memberPredicate the RDF predicate for member resources from the provider's + * query shape + * @see + * Specifying the sahpe of a query + */ + public void setMemberProperty(String memberPredicate) { + this.memberProperty = ModelFactory.createDefaultModel().createProperty(memberPredicate); + } + + /** + * Get the raw Wink client response to a query. + *

+ * NOTE: Using this method and consuming the response will make other methods + * which examine the response unavailable (Examples: getMemberUrls(), next() and hasNext()). + * When this method is invoked, the consumer is responsible for OSLC page processing + * + * @return + */ + public Response getRawResponse() { + return response; + } + + private Selector getMemberSelector() { + if ("true".equalsIgnoreCase(System.getProperty(SELECT_ANY_MEMBER))) { + return new AnyMemberSelector(membersResource); + } + + return new SimpleSelector(membersResource, memberProperty, (RDFNode) null); + } + + /** + * Return the subject URLs of the query response. The URLs are the location of all artifacts + * which satisfy the query conditions. + *

+ * NOTE: Using this method consumes the query response and makes other methods + * which examine the response unavailable (Example: getRawResponse(). + * + * @return + */ + public String[] getMembersUrls() { + initializeRdf(); + ArrayList membersUrls = new ArrayList<>(); Selector select = getMemberSelector(); - StmtIterator iter = rdfModel.listStatements(select); - while (iter.hasNext()) { - Statement member = iter.next(); - membersUrls.add(member.getResource().getURI()); - } - return membersUrls.toArray(new String[membersUrls.size()]); - } - - /** - * Return the enumeration of queried results from this page - * - * @return member statements from current page. - */ + StmtIterator iter = rdfModel.listStatements(select); + while (iter.hasNext()) { + Statement member = iter.next(); + membersUrls.add(member.getResource().getURI()); + } + return membersUrls.toArray(new String[membersUrls.size()]); + } + + /** + * Return the enumeration of queried results from this page + * + * @return member statements from current page. + */ public Iterable getMembers(final Class clazz) { initializeRdf(); @@ -314,11 +327,12 @@ public T next() { Statement member = iter.next(); try { - return (T) JenaModelHelper.fromJenaResource((Resource) member.getObject(), clazz); + return (T) JenaModelHelper.fromJenaResource((Resource) member.getObject(), + clazz); } catch (DatatypeConfigurationException | IllegalAccessException | InvocationTargetException | InstantiationException | - OslcCoreApplicationException - | NoSuchMethodException | URISyntaxException e) { + OslcCoreApplicationException | NoSuchMethodException | + URISyntaxException e) { throw new LyoModelException(e); } } diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcQueryResultTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcQueryResultTest.java index 1c289a5ed..e4bf62fab 100644 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcQueryResultTest.java +++ b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcQueryResultTest.java @@ -13,11 +13,7 @@ */ package org.eclipse.lyo.client; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.when; - -import java.io.InputStream; - +import jakarta.ws.rs.core.Response; import org.eclipse.lyo.client.query.OslcQuery; import org.eclipse.lyo.client.query.OslcQueryParameters; import org.eclipse.lyo.client.query.OslcQueryResult; @@ -25,91 +21,98 @@ import org.junit.Test; import org.mockito.Mockito; -import jakarta.ws.rs.core.Response; +import java.io.InputStream; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; /** * @author Samuel Padgett */ public class OslcQueryResultTest { - @Before - public void clearPublicURISystemProperty() { - System.clearProperty(OslcQueryResult.SELECT_ANY_MEMBER); - } - - @Test - public void testEmpty() { - Response mockedResponse = mockClientResponse("/emptyQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setWhere("dceterms:identifier=3"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", params); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(0, result.getMembersUrls().length); - } - - @Test - public void testNoParameters() { - Response mockedResponse = mockClientResponse("/noParamQuery.rdf"); - - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(2, result.getMembersUrls().length); - } + @Before + public void clearPublicURISystemProperty() { + System.clearProperty(OslcQueryResult.SELECT_ANY_MEMBER); + } + + @Test + public void testEmpty() { + Response mockedResponse = mockClientResponse("/emptyQuery.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setWhere("dceterms:identifier=3"); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", + params); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(0, result.getMembersUrls().length); + } + + @Test + public void testNoParameters() { + Response mockedResponse = mockClientResponse("/noParamQuery.rdf"); + + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query"); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(2, result.getMembersUrls().length); + } @Test public void testFolderQuery() { Response mockedResponse = mockClientResponse("/queryFolderResponse.rdf"); OslcQueryParameters params = new OslcQueryParameters(); - params.setPrefix("dcterms=,nav="); + params.setPrefix("dcterms=,nav="); params.setSelect("*"); - OslcQuery query = new OslcQuery(new OslcClient(), "https://192.168.99.3:9443/rm/folders", params); + OslcQuery query = new OslcQuery(new OslcClient(), "https://192.168.99.3:9443/rm/folders", + params); OslcQueryResult result = new OslcQueryResult(query, mockedResponse); assertEquals(1, result.getMembersUrls().length); } - @Test - public void testQuery() { - Response mockedResponse = mockClientResponse("/queryResponse.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setWhere("ex:product=\"Product A\""); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", params); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(2, result.getMembersUrls().length); - } - - @Test - public void testBlogQuery() { - Response mockedResponse = mockClientResponse("/blogQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setSelect("dcterms:title"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - result.setMemberProperty("http://open-services.net/ns/bogus/blogs#comment"); - assertEquals(5, result.getMembersUrls().length); - } - - @Test - public void testAnyMember() { - System.setProperty(OslcQueryResult.SELECT_ANY_MEMBER, "true"); - Response mockedResponse = mockClientResponse("/blogQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setSelect("dcterms:title"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(5, result.getMembersUrls().length); - } - - private Response mockClientResponse(String file) { - final InputStream is = OslcQueryResultTest.class.getResourceAsStream(file); - Response mockedResponse = Mockito.mock(Response.class); - when(mockedResponse.readEntity(InputStream.class)).thenReturn(is); - - return mockedResponse; + @Test + public void testQuery() { + Response mockedResponse = mockClientResponse("/queryResponse.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setWhere("ex:product=\"Product A\""); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", + params); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(2, result.getMembersUrls().length); + } + + @Test + public void testBlogQuery() { + Response mockedResponse = mockClientResponse("/blogQuery.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setSelect("dcterms:title"); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + result.setMemberProperty("http://open-services.net/ns/bogus/blogs#comment"); + assertEquals(5, result.getMembersUrls().length); + } + + @Test + public void testAnyMember() { + System.setProperty(OslcQueryResult.SELECT_ANY_MEMBER, "true"); + Response mockedResponse = mockClientResponse("/blogQuery.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setSelect("dcterms:title"); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(5, result.getMembersUrls().length); + } + + private Response mockClientResponse(String file) { + final InputStream is = OslcQueryResultTest.class.getResourceAsStream(file); + Response mockedResponse = Mockito.mock(Response.class); + when(mockedResponse.readEntity(InputStream.class)).thenReturn(is); + + return mockedResponse; } } From e75e8db30fb6921395fd2ef1105007f614a52ff4 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Tue, 5 Nov 2024 23:29:27 +0100 Subject: [PATCH 10/15] fix: update the responseinfo locating logic --- .../lyo/client/query/OslcQueryResult.java | 62 ++++++++- .../lyo/client/OslcQueryResultTest.java | 118 ------------------ .../test/resources/simplelogger.properties | 2 + 3 files changed, 58 insertions(+), 124 deletions(-) delete mode 100644 client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcQueryResultTest.java create mode 100644 client/oslc-client/src/test/resources/simplelogger.properties diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index c71096829..3ebfcab48 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -30,6 +30,8 @@ import org.eclipse.lyo.oslc4j.core.exception.OslcCoreApplicationException; import org.eclipse.lyo.oslc4j.core.model.OslcConstants; import org.eclipse.lyo.oslc4j.provider.jena.JenaModelHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.xml.datatype.DatatypeConfigurationException; import java.io.InputStream; @@ -47,6 +49,7 @@ * This class is not currently thread safe. */ public class OslcQueryResult implements Iterator { + private static final Logger log = LoggerFactory.getLogger(OslcQueryResult.class); /** * The default member property to look for in OSLC query results * (rdfs:member). Can be changed using {@link #setMemberProperty(String)}. @@ -131,23 +134,70 @@ private synchronized void initializeRdf() { List responseInfos = iter.toList(); infoResource = null; + membersResource = rdfModel.getResource(query.getCapabilityUrl()); + + if (responseInfos.isEmpty()) { + return; + } + infoResource = tryFindOnlyResponseInfo(responseInfos); - if (infoResource == null && responseInfos.size() > 1) { - infoResource = tryFindExactResponseInfoUri(responseInfos); + if (infoResource == null) { + log.trace("Cannot find exactly one ResponseInfo"); + } else { + log.debug("Found exactly one ResponseInfo"); + return; } - if (infoResource == null && responseInfos.size() > 1) { - infoResource = tryFindPrefixedResponseInfoUri(responseInfos); + + infoResource = tryFindOnlyWithNextPage(responseInfos); + if (infoResource == null) { + log.trace("Cannot find exactly one ResponseInfo with nextPage"); + } else { + log.debug("Found exactly one ResponseInfo with nextPage"); + return; + } + + infoResource = tryFindExactResponseInfoUri(responseInfos); + if (infoResource == null) { + log.trace("Cannot a ResponseInfo whose URI matches the query URI exactly"); + } else { + log.debug("Found a ResponseInfo whose URI matches the query URI exactly"); + return; + } + + infoResource = tryFindPrefixedResponseInfoUri(responseInfos); + if (infoResource == null) { + log.trace("Cannot find exactly one ResponseInfo whose URI starts with the query URI"); + } else { + log.debug("Found exactly one ResponseInfo whose URI starts with the query URI"); + return; } + if (infoResource == null) { - // TODO: also check for oslc:nextPage before giving up throw new IllegalStateException("Failed to find an appropriate ResponseInfo " + "object"); } - membersResource = rdfModel.getResource(query.getCapabilityUrl()); } } + /** + * Extracts a ResourceInfo resource if one and only one has the same prefix as the query URI. + * + * @param responseInfos from OSLC Query results + * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy + * @throws IllegalStateException if multiple resources satisfy the same condition + */ + private Resource tryFindOnlyWithNextPage(List responseInfos) { + Property nextPagePredicate = rdfModel.getProperty(OslcConstants.OSLC_CORE_NAMESPACE, + "nextPage"); + var responsesWithNextPage = + responseInfos.stream().filter(ri -> ri.getProperty(nextPagePredicate) != null).toList(); + if (responsesWithNextPage.size() == 1) { + return responsesWithNextPage.get(0); + } + return null; + } + /** * Extracts a ResourceInfo resource if one and only one has the same prefix as the query URI. * diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcQueryResultTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcQueryResultTest.java deleted file mode 100644 index e4bf62fab..000000000 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/OslcQueryResultTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2020 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License 1.0 - * which is available at http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.lyo.client; - -import jakarta.ws.rs.core.Response; -import org.eclipse.lyo.client.query.OslcQuery; -import org.eclipse.lyo.client.query.OslcQueryParameters; -import org.eclipse.lyo.client.query.OslcQueryResult; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import java.io.InputStream; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -/** - * @author Samuel Padgett - */ -public class OslcQueryResultTest { - @Before - public void clearPublicURISystemProperty() { - System.clearProperty(OslcQueryResult.SELECT_ANY_MEMBER); - } - - @Test - public void testEmpty() { - Response mockedResponse = mockClientResponse("/emptyQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setWhere("dceterms:identifier=3"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", - params); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(0, result.getMembersUrls().length); - } - - @Test - public void testNoParameters() { - Response mockedResponse = mockClientResponse("/noParamQuery.rdf"); - - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(2, result.getMembersUrls().length); - } - - @Test - public void testFolderQuery() { - Response mockedResponse = mockClientResponse("/queryFolderResponse.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setPrefix("dcterms=,nav="); - params.setSelect("*"); - - OslcQuery query = new OslcQuery(new OslcClient(), "https://192.168.99.3:9443/rm/folders", - params); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(1, result.getMembersUrls().length); - } - - @Test - public void testQuery() { - Response mockedResponse = mockClientResponse("/queryResponse.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setWhere("ex:product=\"Product A\""); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", - params); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(2, result.getMembersUrls().length); - } - - @Test - public void testBlogQuery() { - Response mockedResponse = mockClientResponse("/blogQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setSelect("dcterms:title"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - result.setMemberProperty("http://open-services.net/ns/bogus/blogs#comment"); - assertEquals(5, result.getMembersUrls().length); - } - - @Test - public void testAnyMember() { - System.setProperty(OslcQueryResult.SELECT_ANY_MEMBER, "true"); - Response mockedResponse = mockClientResponse("/blogQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setSelect("dcterms:title"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(5, result.getMembersUrls().length); - } - - private Response mockClientResponse(String file) { - final InputStream is = OslcQueryResultTest.class.getResourceAsStream(file); - Response mockedResponse = Mockito.mock(Response.class); - when(mockedResponse.readEntity(InputStream.class)).thenReturn(is); - - return mockedResponse; - } - -} diff --git a/client/oslc-client/src/test/resources/simplelogger.properties b/client/oslc-client/src/test/resources/simplelogger.properties new file mode 100644 index 000000000..9eb12ca52 --- /dev/null +++ b/client/oslc-client/src/test/resources/simplelogger.properties @@ -0,0 +1,2 @@ +org.slf4j.simpleLogger.defaultLogLevel=info +org.slf4j.simpleLogger.log.org.eclipse.lyo=trace From c03f7efb9eb5876bc0d325e311f0ed3ba2d9ea6e Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Tue, 5 Nov 2024 23:30:19 +0100 Subject: [PATCH 11/15] reformat --- .../lyo/client/query/OslcQueryResult.java | 8 +- .../lyo/client/query/OslcQueryResultTest.java | 148 +++++++++--------- 2 files changed, 79 insertions(+), 77 deletions(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index 3ebfcab48..9dc115749 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -166,7 +166,7 @@ private synchronized void initializeRdf() { infoResource = tryFindPrefixedResponseInfoUri(responseInfos); if (infoResource == null) { - log.trace("Cannot find exactly one ResponseInfo whose URI starts with the query URI"); + log.trace("Cannot find exactly one ResponseInfo whose URI starts with the query " + "URI"); } else { log.debug("Found exactly one ResponseInfo whose URI starts with the query URI"); return; @@ -211,8 +211,7 @@ private Resource tryFindPrefixedResponseInfoUri(List responseInfos) { if (filteredObjects.size() == 1) { return filteredObjects.get(0); } else if (filteredObjects.size() > 1) { - throw new IllegalStateException("Multiple ResponseInfo objects found starting with " + - "the same Query URI"); + throw new IllegalStateException("Multiple ResponseInfo objects found starting with " + "the same Query URI"); } return null; } @@ -231,8 +230,7 @@ private Resource tryFindExactResponseInfoUri(List responseInfos) { if (filteredObjects.size() == 1) { return filteredObjects.get(0); } else if (filteredObjects.size() > 1) { - throw new IllegalStateException("Multiple ResponseInfo objects found with the same " + - "URI"); + throw new IllegalStateException("Multiple ResponseInfo objects found with the same " + "URI"); } return null; } diff --git a/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java b/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java index 4f1dfc44f..126069d24 100644 --- a/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java +++ b/client/oslc-client/src/test/java/org/eclipse/lyo/client/query/OslcQueryResultTest.java @@ -13,94 +13,97 @@ */ package org.eclipse.lyo.client.query; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.when; - -import java.io.InputStream; - +import jakarta.ws.rs.core.Response; import org.eclipse.lyo.client.OslcClient; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -import jakarta.ws.rs.core.Response; +import java.io.InputStream; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; /** * @author Samuel Padgett */ public class OslcQueryResultTest { - @Before - public void clearPublicURISystemProperty() { - System.clearProperty(OslcQueryResult.SELECT_ANY_MEMBER); - } - - @Test - public void testEmpty() { - Response mockedResponse = mockClientResponse("/emptyQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setWhere("dceterms:identifier=3"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", params); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(0, result.getMembersUrls().length); - } - - @Test - public void testNoParameters() { - Response mockedResponse = mockClientResponse("/noParamQuery.rdf"); - - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(2, result.getMembersUrls().length); - } + @Before + public void clearPublicURISystemProperty() { + System.clearProperty(OslcQueryResult.SELECT_ANY_MEMBER); + } + + @Test + public void testEmpty() { + Response mockedResponse = mockClientResponse("/emptyQuery.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setWhere("dceterms:identifier=3"); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", + params); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(0, result.getMembersUrls().length); + } + + @Test + public void testNoParameters() { + Response mockedResponse = mockClientResponse("/noParamQuery.rdf"); + + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query"); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(2, result.getMembersUrls().length); + } @Test public void testFolderQuery() { Response mockedResponse = mockClientResponse("/queryFolderResponse.rdf"); OslcQueryParameters params = new OslcQueryParameters(); - params.setPrefix("dcterms=,nav="); + params.setPrefix("dcterms=,nav="); params.setSelect("*"); - OslcQuery query = new OslcQuery(new OslcClient(), "https://192.168.99.3:9443/rm/folders", params); + OslcQuery query = new OslcQuery(new OslcClient(), "https://192.168.99.3:9443/rm/folders", + params); OslcQueryResult result = new OslcQueryResult(query, mockedResponse); assertEquals(1, result.getMembersUrls().length); } - @Test - public void testQuery() { - Response mockedResponse = mockClientResponse("/queryResponse.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setWhere("ex:product=\"Product A\""); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", params); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(2, result.getMembersUrls().length); - } - - @Test - public void testBlogQuery() { - Response mockedResponse = mockClientResponse("/blogQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setSelect("dcterms:title"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - result.setMemberProperty("http://open-services.net/ns/bogus/blogs#comment"); - assertEquals(5, result.getMembersUrls().length); - } - - @Test - public void testAnyMember() { - System.setProperty(OslcQueryResult.SELECT_ANY_MEMBER, "true"); - Response mockedResponse = mockClientResponse("/blogQuery.rdf"); - - OslcQueryParameters params = new OslcQueryParameters(); - params.setSelect("dcterms:title"); - OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); - OslcQueryResult result = new OslcQueryResult(query, mockedResponse); - assertEquals(5, result.getMembersUrls().length); - } + @Test + public void testQuery() { + Response mockedResponse = mockClientResponse("/queryResponse.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setWhere("ex:product=\"Product A\""); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/provider/query", + params); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(2, result.getMembersUrls().length); + } + + @Test + public void testBlogQuery() { + Response mockedResponse = mockClientResponse("/blogQuery.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setSelect("dcterms:title"); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + result.setMemberProperty("http://open-services.net/ns/bogus/blogs#comment"); + assertEquals(5, result.getMembersUrls().length); + } + + @Test + public void testAnyMember() { + System.setProperty(OslcQueryResult.SELECT_ANY_MEMBER, "true"); + Response mockedResponse = mockClientResponse("/blogQuery.rdf"); + + OslcQueryParameters params = new OslcQueryParameters(); + params.setSelect("dcterms:title"); + OslcQuery query = new OslcQuery(new OslcClient(), "http://example.com/query"); + OslcQueryResult result = new OslcQueryResult(query, mockedResponse); + assertEquals(5, result.getMembersUrls().length); + } @Test public void testMultiResponseInfos() { @@ -110,17 +113,18 @@ public void testMultiResponseInfos() { OslcQueryParameters params = new OslcQueryParameters(); params.setSelect("dcterms:title"); - OslcQuery query = new OslcQuery(new OslcClient(), "https://nordic.clm.ibmcloud.com/ccm/oslc/contexts/_2nC4UBNvEeutmoeSPr3-Ag/workitems"); + OslcQuery query = new OslcQuery(new OslcClient(), "https://nordic.clm.ibmcloud" + + ".com/ccm/oslc/contexts/_2nC4UBNvEeutmoeSPr3-Ag/workitems"); OslcQueryResult result = new OslcQueryResult(query, mockedResponse); assertEquals(20, result.getMembersUrls().length); } - private Response mockClientResponse(String file) { - final InputStream is = OslcQueryResultTest.class.getResourceAsStream(file); - Response mockedResponse = Mockito.mock(Response.class); - when(mockedResponse.readEntity(InputStream.class)).thenReturn(is); + private Response mockClientResponse(String file) { + final InputStream is = OslcQueryResultTest.class.getResourceAsStream(file); + Response mockedResponse = Mockito.mock(Response.class); + when(mockedResponse.readEntity(InputStream.class)).thenReturn(is); - return mockedResponse; + return mockedResponse; } } From 81c335549286d00644c8ba5cbcd81f816a045228 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Tue, 5 Nov 2024 23:33:43 +0100 Subject: [PATCH 12/15] docs: fix up javadoc and add log warn --- .../java/org/eclipse/lyo/client/query/OslcQueryResult.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index 9dc115749..36a2ce02e 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -181,11 +181,11 @@ private synchronized void initializeRdf() { } /** - * Extracts a ResourceInfo resource if one and only one has the same prefix as the query URI. + * Extracts a ResourceInfo resource if one and only one has a property with the nextPage + * predicate. * * @param responseInfos from OSLC Query results * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy - * @throws IllegalStateException if multiple resources satisfy the same condition */ private Resource tryFindOnlyWithNextPage(List responseInfos) { Property nextPagePredicate = rdfModel.getProperty(OslcConstants.OSLC_CORE_NAMESPACE, @@ -195,6 +195,9 @@ private Resource tryFindOnlyWithNextPage(List responseInfos) { if (responsesWithNextPage.size() == 1) { return responsesWithNextPage.get(0); } + else if (responsesWithNextPage.size() > 1) { + log.warn("Multiple ResponseInfo objects found with nextPage predicate"); + } return null; } From 49dd1fa83a1ed0f0ffce43df52d6e24c0dca9cb2 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Tue, 5 Nov 2024 23:42:57 +0100 Subject: [PATCH 13/15] fix: do not throw exception if multiple response infos have the same prefix while anomalous, it's not forbidden --- .../java/org/eclipse/lyo/client/query/OslcQueryResult.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index 36a2ce02e..e9a6eb0fb 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -206,7 +206,6 @@ else if (responsesWithNextPage.size() > 1) { * * @param responseInfos from OSLC Query results * @return a ResourceInfo resource if one satisfies the conditions; null if none satisfy - * @throws IllegalStateException if multiple resources satisfy the same condition */ private Resource tryFindPrefixedResponseInfoUri(List responseInfos) { List filteredObjects = @@ -214,7 +213,7 @@ private Resource tryFindPrefixedResponseInfoUri(List responseInfos) { if (filteredObjects.size() == 1) { return filteredObjects.get(0); } else if (filteredObjects.size() > 1) { - throw new IllegalStateException("Multiple ResponseInfo objects found starting with " + "the same Query URI"); + log.warn("Multiple ResponseInfo objects found starting with " + "the same Query URI"); } return null; } From 1c30b09c246754b12012b3242b7c1e9493e6f372 Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Tue, 5 Nov 2024 23:45:47 +0100 Subject: [PATCH 14/15] chore: clean up --- .../org/eclipse/lyo/client/query/OslcQueryResult.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java index e9a6eb0fb..04094c85f 100644 --- a/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java +++ b/client/oslc-client/src/main/java/org/eclipse/lyo/client/query/OslcQueryResult.java @@ -166,15 +166,14 @@ private synchronized void initializeRdf() { infoResource = tryFindPrefixedResponseInfoUri(responseInfos); if (infoResource == null) { - log.trace("Cannot find exactly one ResponseInfo whose URI starts with the query " + "URI"); + log.trace("Cannot find exactly one ResponseInfo whose URI starts with the query URI"); } else { log.debug("Found exactly one ResponseInfo whose URI starts with the query URI"); return; } if (infoResource == null) { - throw new IllegalStateException("Failed to find an appropriate ResponseInfo " + - "object"); + throw new IllegalStateException("Failed to find an appropriate ResponseInfo object"); } } @@ -213,7 +212,7 @@ private Resource tryFindPrefixedResponseInfoUri(List responseInfos) { if (filteredObjects.size() == 1) { return filteredObjects.get(0); } else if (filteredObjects.size() > 1) { - log.warn("Multiple ResponseInfo objects found starting with " + "the same Query URI"); + log.warn("Multiple ResponseInfo objects found starting with the same Query URI"); } return null; } @@ -232,7 +231,7 @@ private Resource tryFindExactResponseInfoUri(List responseInfos) { if (filteredObjects.size() == 1) { return filteredObjects.get(0); } else if (filteredObjects.size() > 1) { - throw new IllegalStateException("Multiple ResponseInfo objects found with the same " + "URI"); + throw new IllegalStateException("Multiple ResponseInfo objects found with the same URI"); } return null; } From 679393a7b6b02a9822fbc24dc7db8e1da74d099c Mon Sep 17 00:00:00 2001 From: Andrew Berezovskyi Date: Wed, 6 Nov 2024 20:21:33 +0100 Subject: [PATCH 15/15] docs --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 949347b8b..1873f1be6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,9 @@ ### Deprecated ### Removed + - Dependency to deprecated oslc4j-json4j-provider + ### Fixed - Client now picks the correct ResponseInfo object when an OSLC Query response contains multiple ResponseInfo objects.