Skip to content

Commit bf7a543

Browse files
authored
Merge pull request #188 from bosch-io/feature/retrieve-policy-fields
Add option for field selectors and options to RetrievePolicy API
2 parents bba1690 + bd8c701 commit bf7a543

File tree

7 files changed

+144
-59
lines changed

7 files changed

+144
-59
lines changed

java/src/main/java/org/eclipse/ditto/client/internal/OutgoingMessageFactory.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ public RetrieveThing retrieveThing(final ThingId thingId,
222222
final Option<?>... options) {
223223

224224
return RetrieveThing.getBuilder(thingId,
225-
buildDittoHeaders(EnumSet.of(CONDITION, LIVE_CHANNEL_CONDITION), options))
225+
buildDittoHeaders(EnumSet.of(CONDITION, LIVE_CHANNEL_CONDITION), options))
226226
.withSelectedFields(JsonFactory.newFieldSelector(fields))
227227
.build();
228228
}
@@ -298,16 +298,17 @@ public ModifyPolicy updatePolicy(final Policy policy, final Option<?>... options
298298
return ModifyPolicy.of(policyId, policy, headers);
299299
}
300300

301-
/**
302-
* Builds a command to retrieve the policy with ID {@code policyId}.
303-
*
304-
* @param policyId the policy to retrieve.
305-
* @return the {@link RetrievePolicy} command.
306-
* @throws NullPointerException if the policyId is {@code null}.
307-
* @since 1.1.0
308-
*/
309-
public RetrievePolicy retrievePolicy(final PolicyId policyId) {
310-
return RetrievePolicy.of(policyId, buildDittoHeaders(Collections.emptySet()));
301+
public RetrievePolicy retrievePolicy(final PolicyId policyId, final Option<?>... options) {
302+
return RetrievePolicy.of(policyId, buildDittoHeaders(Collections.emptySet(), options));
303+
}
304+
305+
public RetrievePolicy retrievePolicy(final PolicyId policyId,
306+
final Iterable<JsonPointer> fields,
307+
final Option<?>... options) {
308+
309+
return RetrievePolicy.of(policyId,
310+
buildDittoHeaders(Collections.emptySet(), options),
311+
JsonFactory.newFieldSelector(fields));
311312
}
312313

313314
/**

java/src/main/java/org/eclipse/ditto/client/live/commands/query/RetrieveThingsLiveCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
import javax.annotation.Nonnull;
1818

19+
import org.eclipse.ditto.base.model.signals.commands.WithNamespace;
1920
import org.eclipse.ditto.client.live.commands.base.LiveCommand;
2021
import org.eclipse.ditto.things.model.ThingId;
21-
import org.eclipse.ditto.base.model.signals.commands.WithNamespace;
2222
import org.eclipse.ditto.things.model.signals.commands.WithSelectedFields;
2323
import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThings;
2424

java/src/main/java/org/eclipse/ditto/client/policies/Policies.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
import java.util.concurrent.CompletionStage;
1717

1818
import org.eclipse.ditto.client.options.Option;
19+
import org.eclipse.ditto.json.JsonFieldSelector;
1920
import org.eclipse.ditto.json.JsonObject;
2021
import org.eclipse.ditto.policies.model.Policy;
2122
import org.eclipse.ditto.policies.model.PolicyId;
23+
import org.eclipse.ditto.things.model.Thing;
2224

2325
/**
2426
* A {@code Policy} provides the basic functionality, which can be used to manage (i.e. create and delete)
@@ -153,12 +155,54 @@ public interface Policies {
153155
CompletionStage<Void> delete(PolicyId policyId, Option<?>... options);
154156

155157
/**
156-
* Gets the {@link org.eclipse.ditto.policies.model.Policy} specified by the given identifier.
158+
* Gets the {@code Policy} specified by the given identifier.
157159
*
158160
* @param policyId the identifier of the Policy to be retrieved.
159161
* @return CompletionStage providing the requested Policy or a specific
160162
* {@link org.eclipse.ditto.base.model.exceptions.DittoRuntimeException} if the operation failed
161163
* @throws IllegalArgumentException if {@code policyId} is {@code null}.
162164
*/
163165
CompletionStage<Policy> retrieve(PolicyId policyId);
166+
167+
168+
/**
169+
* Gets the {@code Policy} specified by the given identifier with the given options.
170+
*
171+
* @param options options that determine the behaviour of this method, see
172+
* {@link org.eclipse.ditto.client.options.Options}.
173+
* @return CompletionStage providing the requested {@link Thing} or a specific
174+
* {@link org.eclipse.ditto.base.model.exceptions.DittoRuntimeException} if the operation failed.
175+
* @throws NullPointerException if {@code options} is {@code null}.
176+
* @throws IllegalArgumentException if {@code options} contains an option that is not allowed for retrieving
177+
* a thing.
178+
* @since 2.4.0
179+
*/
180+
CompletionStage<Policy> retrieve(PolicyId policyId, Option<?>... options);
181+
182+
/**
183+
* Retrieve the {@code Policy} specified by the given identifier, containing the fields specified by
184+
* the given {@code fieldSelector}.
185+
*
186+
* @param fieldSelector a field selector object allowing to select a subset of fields on the Policy to be retrieved.
187+
* @return CompletionStage providing the requested {@link Policy} or a specific
188+
* {@link org.eclipse.ditto.base.model.exceptions.DittoRuntimeException} if the operation failed
189+
* @since 2.4.0
190+
*/
191+
CompletionStage<Policy> retrieve(PolicyId policyId, JsonFieldSelector fieldSelector);
192+
193+
/**
194+
* Gets the {@code Policy} specified by the given identifier with the given options, containing the fields
195+
* specified by the given {@code fieldSelector}.
196+
*
197+
* @param fieldSelector a field selector object allowing to select a subset of fields on the Policy to be retrieved.
198+
* @param options options that determine the behaviour of this method, see
199+
* {@link org.eclipse.ditto.client.options.Options}.
200+
* @return CompletionStage providing the requested {@link Policy} or a specific
201+
* {@link org.eclipse.ditto.base.model.exceptions.DittoRuntimeException} if the operation failed.
202+
* @throws NullPointerException if any argument is {@code null}.
203+
* @throws IllegalArgumentException if {@code options} contains an option that is not allowed for retrieving
204+
* a policy.
205+
* @since 2.4.0
206+
*/
207+
CompletionStage<Policy> retrieve(PolicyId policyId, JsonFieldSelector fieldSelector, Option<?>... options);
164208
}

java/src/main/java/org/eclipse/ditto/client/policies/internal/PoliciesImpl.java

Lines changed: 27 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,21 @@
2020

2121
import javax.annotation.Nonnull;
2222

23-
import org.eclipse.ditto.base.model.acks.AcknowledgementLabel;
24-
import org.eclipse.ditto.base.model.acks.DittoAcknowledgementLabel;
25-
import org.eclipse.ditto.base.model.headers.DittoHeaders;
26-
import org.eclipse.ditto.base.model.headers.entitytag.EntityTag;
2723
import org.eclipse.ditto.client.internal.AbstractHandle;
2824
import org.eclipse.ditto.client.internal.OutgoingMessageFactory;
2925
import org.eclipse.ditto.client.internal.bus.PointerBus;
3026
import org.eclipse.ditto.client.messaging.MessagingProvider;
3127
import org.eclipse.ditto.client.options.Option;
3228
import org.eclipse.ditto.client.policies.Policies;
29+
import org.eclipse.ditto.json.JsonFieldSelector;
3330
import org.eclipse.ditto.json.JsonObject;
3431
import org.eclipse.ditto.json.JsonValue;
32+
import org.eclipse.ditto.base.model.acks.AcknowledgementLabel;
33+
import org.eclipse.ditto.base.model.acks.DittoAcknowledgementLabel;
3534
import org.eclipse.ditto.policies.model.PoliciesModelFactory;
3635
import org.eclipse.ditto.policies.model.Policy;
3736
import org.eclipse.ditto.policies.model.PolicyId;
38-
import org.eclipse.ditto.policies.model.PolicyRevision;
37+
import org.eclipse.ditto.protocol.TopicPath;
3938
import org.eclipse.ditto.policies.model.signals.commands.modify.CreatePolicy;
4039
import org.eclipse.ditto.policies.model.signals.commands.modify.CreatePolicyResponse;
4140
import org.eclipse.ditto.policies.model.signals.commands.modify.DeletePolicy;
@@ -44,7 +43,6 @@
4443
import org.eclipse.ditto.policies.model.signals.commands.modify.PolicyModifyCommandResponse;
4544
import org.eclipse.ditto.policies.model.signals.commands.query.RetrievePolicy;
4645
import org.eclipse.ditto.policies.model.signals.commands.query.RetrievePolicyResponse;
47-
import org.eclipse.ditto.protocol.TopicPath;
4846

4947
/**
5048
* Default implementation for {@link Policies}.
@@ -78,44 +76,14 @@ public static PoliciesImpl newInstance(final MessagingProvider messagingProvider
7876
return new PoliciesImpl(messagingProvider, outgoingMessageFactory, bus);
7977
}
8078

81-
private static Optional<PolicyRevision> getRevisionFromDittoHeaders(final DittoHeaders dittoHeaders) {
82-
return dittoHeaders
83-
.getETag()
84-
.map(EntityTag::getOpaqueTag)
85-
.filter(tag -> tag.contains("rev:"))
86-
.map(tag -> tag.replace("rev:", "").replaceAll("\"", ""))
87-
.map(Long::parseLong)
88-
.map(PolicyRevision::newInstance);
89-
}
90-
91-
private static Policy setRevisionToPolicy(final PolicyRevision policyRevision, final Policy policy) {
92-
return policy.toBuilder()
93-
.setRevision(policyRevision)
94-
.build();
95-
}
96-
97-
private static Policy appendRevisionFromHeadersIfNeeded(final Policy policy, final DittoHeaders dittoHeaders) {
98-
final Policy policyWithRevision;
99-
final Optional<PolicyRevision> revisionFromPolicy = policy.getRevision();
100-
policyWithRevision = revisionFromPolicy
101-
.map(policyRevision -> setRevisionToPolicy(policyRevision, policy))
102-
.orElseGet(() -> getRevisionFromDittoHeaders(dittoHeaders)
103-
.map(revisionFromHeaders -> setRevisionToPolicy(revisionFromHeaders, policy))
104-
.orElse(policy));
105-
return policyWithRevision;
106-
}
107-
10879
@Override
10980
public CompletionStage<Policy> create(final Policy policy, final Option<?>... options) {
11081
argumentNotNull(policy);
11182
assertThatPolicyHasId(policy);
11283

11384
final CreatePolicy command = outgoingMessageFactory.createPolicy(policy, options);
11485
return askPolicyCommand(command, CreatePolicyResponse.class,
115-
response -> response.getPolicyCreated()
116-
.map(policyFromResponse -> appendRevisionFromHeadersIfNeeded(policyFromResponse,
117-
response.getDittoHeaders()))
118-
.orElse(null));
86+
response -> response.getPolicyCreated().orElse(null));
11987
}
12088

12189
@Override
@@ -137,8 +105,6 @@ public CompletionStage<Optional<Policy>> put(final Policy policy, final Option<?
137105
response -> response.getEntity(response.getImplementedSchemaVersion())
138106
.map(JsonValue::asObject)
139107
.map(PoliciesModelFactory::newPolicy)
140-
.map(policyFromResponse -> appendRevisionFromHeadersIfNeeded(policyFromResponse,
141-
response.getDittoHeaders()))
142108
);
143109
}
144110

@@ -176,12 +142,29 @@ public CompletionStage<Void> delete(final PolicyId policyId, final Option<?>...
176142
}
177143

178144
@Override
179-
public CompletionStage<Policy> retrieve(PolicyId policyId) {
145+
public CompletionStage<Policy> retrieve(final PolicyId policyId) {
180146
final RetrievePolicy command = outgoingMessageFactory.retrievePolicy(policyId);
181-
return askPolicyCommand(command, RetrievePolicyResponse.class, response -> {
182-
final Policy policyFromResponse = response.getPolicy();
183-
return appendRevisionFromHeadersIfNeeded(policyFromResponse, response.getDittoHeaders());
184-
});
147+
return askPolicyCommand(command, RetrievePolicyResponse.class, RetrievePolicyResponse::getPolicy);
148+
}
149+
150+
@Override
151+
public CompletionStage<Policy> retrieve(final PolicyId policyId, final Option<?>... options) {
152+
final RetrievePolicy command = outgoingMessageFactory.retrievePolicy(policyId, options);
153+
return askPolicyCommand(command, RetrievePolicyResponse.class, RetrievePolicyResponse::getPolicy);
154+
}
155+
156+
@Override
157+
public CompletionStage<Policy> retrieve(final PolicyId policyId, final JsonFieldSelector fieldSelector) {
158+
final RetrievePolicy command = outgoingMessageFactory.retrievePolicy(policyId, fieldSelector);
159+
return askPolicyCommand(command, RetrievePolicyResponse.class, RetrievePolicyResponse::getPolicy);
160+
}
161+
162+
@Override
163+
public CompletionStage<Policy> retrieve(final PolicyId policyId, final JsonFieldSelector fieldSelector,
164+
final Option<?>... options) {
165+
166+
final RetrievePolicy command = outgoingMessageFactory.retrievePolicy(policyId, fieldSelector, options);
167+
return askPolicyCommand(command, RetrievePolicyResponse.class, RetrievePolicyResponse::getPolicy);
185168
}
186169

187170
private static void assertThatPolicyHasId(final Policy policy) {

java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import static org.eclipse.ditto.client.TestConstants.Policy.POLICY;
1717
import static org.eclipse.ditto.client.TestConstants.Policy.POLICY_ID;
1818
import static org.eclipse.ditto.client.TestConstants.Policy.POLICY_JSON_OBJECT;
19+
import static org.eclipse.ditto.client.TestConstants.Policy.POLICY_REVISION_ONLY_JSON_OBJECT;
20+
import static org.eclipse.ditto.client.TestConstants.Policy.REVISION_ONLY_POLICY;
1921
import static org.eclipse.ditto.client.assertions.ClientAssertions.assertThat;
2022

2123
import java.util.Arrays;
@@ -27,10 +29,11 @@
2729
import java.util.function.Function;
2830

2931
import org.assertj.core.api.Assertions;
32+
import org.eclipse.ditto.base.model.headers.DittoHeaders;
3033
import org.eclipse.ditto.client.internal.AbstractDittoClientTest;
3134
import org.eclipse.ditto.client.options.Options;
3235
import org.eclipse.ditto.json.JsonFactory;
33-
import org.eclipse.ditto.json.JsonMissingFieldException;
36+
import org.eclipse.ditto.json.JsonFieldSelector;
3437
import org.eclipse.ditto.policies.model.Policy;
3538
import org.eclipse.ditto.policies.model.signals.commands.PolicyCommand;
3639
import org.eclipse.ditto.policies.model.signals.commands.PolicyCommandResponse;
@@ -181,6 +184,54 @@ public void testRetrievePolicy() throws Exception {
181184
Assertions.assertThat(retrievePolicyResponse).isCompletedWithValue(POLICY);
182185
}
183186

187+
@Test
188+
public void testRetrievePolicyWithOptions() {
189+
final String correlationId = "abc";
190+
client.policies()
191+
.retrieve(POLICY_ID, Options.headers(DittoHeaders.newBuilder().correlationId(correlationId).build()))
192+
.toCompletableFuture();
193+
final RetrievePolicy command = expectMsgClass(RetrievePolicy.class);
194+
Assertions.assertThat(command.getDittoHeaders().getCorrelationId()).contains(correlationId);
195+
}
196+
197+
@Test
198+
public void testRetrievePolicyWithInvalidOptions() {
199+
Assertions.assertThatIllegalArgumentException().isThrownBy(() -> client.policies()
200+
.retrieve(POLICY_ID, Options.condition("exists(entry)")));
201+
}
202+
203+
@Test
204+
public void testRetrievePolicyWithFieldSelector() throws Exception {
205+
final CompletableFuture<Policy> retrievePolicyResponse = client.policies()
206+
.retrieve(POLICY_ID, JsonFieldSelector.newInstance("_revision"))
207+
.toCompletableFuture();
208+
reply(RetrievePolicyResponse.of(POLICY_ID, POLICY_REVISION_ONLY_JSON_OBJECT,
209+
expectMsgClass(RetrievePolicy.class).getDittoHeaders()));
210+
retrievePolicyResponse.get(TIMEOUT, TIME_UNIT);
211+
Assertions.assertThat(retrievePolicyResponse).isCompletedWithValue(REVISION_ONLY_POLICY);
212+
}
213+
214+
@Test
215+
public void testRetrievePolicyWithFieldSelectorAndOptions() throws Exception {
216+
final String correlationId = "abc";
217+
final CompletableFuture<Policy> retrievePolicyResponse = client.policies()
218+
.retrieve(POLICY_ID, JsonFieldSelector.newInstance("_revision"),
219+
Options.headers(DittoHeaders.newBuilder().correlationId(correlationId).build()))
220+
.toCompletableFuture();
221+
final RetrievePolicy command = expectMsgClass(RetrievePolicy.class);
222+
Assertions.assertThat(command.getDittoHeaders().getCorrelationId()).contains(correlationId);
223+
reply(RetrievePolicyResponse.of(POLICY_ID, POLICY_REVISION_ONLY_JSON_OBJECT,
224+
command.getDittoHeaders()));
225+
retrievePolicyResponse.get(TIMEOUT, TIME_UNIT);
226+
Assertions.assertThat(retrievePolicyResponse).isCompletedWithValue(REVISION_ONLY_POLICY);
227+
}
228+
229+
@Test
230+
public void testRetrievePolicyWithFieldSelectorAndInvalidOptions() {
231+
Assertions.assertThatIllegalArgumentException().isThrownBy(() -> client.policies()
232+
.retrieve(POLICY_ID, JsonFieldSelector.newInstance("_revision"), Options.condition("exists(entry)")));
233+
}
234+
184235
@Test
185236
public void testRetrievePolicyFails() {
186237
assertEventualCompletion(client.policies().retrieve(POLICY_ID).handle((response, error) -> {

java/src/test/java/org/eclipse/ditto/client/TestConstants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ public static final class Policy {
217217
public static final org.eclipse.ditto.policies.model.Policy POLICY =
218218
PoliciesModelFactory.newPolicy(POLICY_JSON_OBJECT);
219219

220+
public static final JsonObject POLICY_REVISION_ONLY_JSON_OBJECT = JsonObject.of("{\n" +
221+
" \"_revision\": " + 1 + "\n" + "}");
222+
223+
public static final org.eclipse.ditto.policies.model.Policy REVISION_ONLY_POLICY =
224+
PoliciesModelFactory.newPolicy(POLICY_REVISION_ONLY_JSON_OBJECT);
225+
220226
}
221227

222228
}

java/src/test/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProviderTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public void connectToUnknownHostWithErrorConsumer() throws Exception {
8383
expectNoMsg(errors);
8484
}
8585

86-
@Test(timeout = 10_000)
86+
@Test(timeout = 15_000)
8787
public void serviceUnavailable() throws Exception {
8888
final int numberOfRecoverableErrors = 3;
8989
final BlockingQueue<ServerSocket> serverSocket = new LinkedBlockingQueue<>();

0 commit comments

Comments
 (0)