From c9e98b26e9ab47e89d5de0d2bdd8515c29b466cf Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Wed, 26 Feb 2020 09:34:03 +0100 Subject: [PATCH 01/23] Issue eclipse/ditto#611: added "ditto-signals-acks" to assembly.xml in order to have it included in required bundles Signed-off-by: Thomas Jaeckle --- java/pom.xml | 5 +++++ java/src/main/assembly/assembly.xml | 1 + 2 files changed, 6 insertions(+) diff --git a/java/pom.xml b/java/pom.xml index ba873ba8..f7536e2b 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -803,6 +803,11 @@ ditto-signals-base ${ditto.version} + + org.eclipse.ditto + ditto-signals-acks + ${ditto.version} + org.eclipse.ditto ditto-signals-commands-base diff --git a/java/src/main/assembly/assembly.xml b/java/src/main/assembly/assembly.xml index a5995633..232cb8be 100755 --- a/java/src/main/assembly/assembly.xml +++ b/java/src/main/assembly/assembly.xml @@ -39,6 +39,7 @@ org.eclipse.ditto:ditto-model-messages org.eclipse.ditto:ditto-model-things org.eclipse.ditto:ditto-signals-base + org.eclipse.ditto:ditto-signals-acks org.eclipse.ditto:ditto-signals-commands-base org.eclipse.ditto:ditto-signals-commands-things org.eclipse.ditto:ditto-signals-commands-messages From 189e21752b5713e290afd1e0ccea97bc7f16f94a Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Tue, 17 Mar 2020 17:26:47 +0100 Subject: [PATCH 02/23] Issue eclipse/ditto#611: adjusted to ditto#611 changes Signed-off-by: Thomas Jaeckle --- .../client/messaging/internal/WebSocketMessagingProvider.java | 2 +- .../src/test/java/org/eclipse/ditto/client/TestConstants.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java index 780e07ae..3535277c 100644 --- a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java +++ b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java @@ -466,7 +466,7 @@ private DittoHeaders adjustHeadersForLive(final WithDittoHeaders withDittoHea return withDittoHeaders.getDittoHeaders().toBuilder() .removeHeader(DittoHeaderDefinition.READ_SUBJECTS.getKey()) - .removeHeader(DittoHeaderDefinition.AUTHORIZATION_SUBJECTS.getKey()) + .removeHeader(DittoHeaderDefinition.AUTHORIZATION_CONTEXT.getKey()) .removeHeader(DittoHeaderDefinition.RESPONSE_REQUIRED.getKey()) .build(); } diff --git a/java/src/test/java/org/eclipse/ditto/client/TestConstants.java b/java/src/test/java/org/eclipse/ditto/client/TestConstants.java index 60170c2c..de321b53 100755 --- a/java/src/test/java/org/eclipse/ditto/client/TestConstants.java +++ b/java/src/test/java/org/eclipse/ditto/client/TestConstants.java @@ -20,6 +20,7 @@ import org.eclipse.ditto.model.base.auth.AuthorizationContext; import org.eclipse.ditto.model.base.auth.AuthorizationModelFactory; import org.eclipse.ditto.model.base.auth.AuthorizationSubject; +import org.eclipse.ditto.model.base.auth.DittoAuthorizationContextType; import org.eclipse.ditto.model.things.AccessControlList; import org.eclipse.ditto.model.things.AclEntry; import org.eclipse.ditto.model.things.Attributes; @@ -63,7 +64,8 @@ public static final class Authorization { * An Authorization Context which contains all known Authorization Subjects. */ public static final AuthorizationContext AUTH_CONTEXT = - AuthorizationModelFactory.newAuthContext(AUTH_SUBJECT_OLDMAN, AUTH_SUBJECT_GRIMES); + AuthorizationModelFactory.newAuthContext(DittoAuthorizationContextType.UNSPECIFIED, + AUTH_SUBJECT_OLDMAN, AUTH_SUBJECT_GRIMES); /** * The known ACL entry of John Oldman. From 30e940b68959c88ab4e82afe7bc3725bc4c71c1b Mon Sep 17 00:00:00 2001 From: Juergen Fickel Date: Fri, 20 Mar 2020 14:26:29 +0100 Subject: [PATCH 03/23] Issue #611: Adjusted some builders: * Added missing null-checks. * Removed superfluous null-checks to make fluent API more fluent. * Made constructors private as the builder should not be directly instantiated. Signed-off-by: Juergen Fickel --- .../AuthenticationConfiguration.java | 4 +- ...redentialsAuthenticationConfiguration.java | 58 ++++++++++--------- .../configuration/MessagingConfiguration.java | 4 +- .../configuration/ProxyConfiguration.java | 46 ++++++++------- .../WebSocketMessagingConfiguration.java | 35 ++++++----- .../internal/WebSocketMessagingProvider.java | 35 ++++++----- 6 files changed, 103 insertions(+), 79 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/configuration/AuthenticationConfiguration.java b/java/src/main/java/org/eclipse/ditto/client/configuration/AuthenticationConfiguration.java index 47efcfdb..51a8501f 100755 --- a/java/src/main/java/org/eclipse/ditto/client/configuration/AuthenticationConfiguration.java +++ b/java/src/main/java/org/eclipse/ditto/client/configuration/AuthenticationConfiguration.java @@ -15,6 +15,8 @@ import java.util.Map; import java.util.Optional; +import javax.annotation.Nullable; + /** * Interface for configuration provider specifying the necessary information for authenticating a client at Eclipse * Ditto. @@ -64,7 +66,7 @@ interface Builder { * @param proxyConfiguration the proxy configuration to set. * @return this builder. */ - Builder proxyConfiguration(ProxyConfiguration proxyConfiguration); + Builder proxyConfiguration(@Nullable ProxyConfiguration proxyConfiguration); /** * Build the authentication configuration. diff --git a/java/src/main/java/org/eclipse/ditto/client/configuration/ClientCredentialsAuthenticationConfiguration.java b/java/src/main/java/org/eclipse/ditto/client/configuration/ClientCredentialsAuthenticationConfiguration.java index da220d0a..1ec36218 100644 --- a/java/src/main/java/org/eclipse/ditto/client/configuration/ClientCredentialsAuthenticationConfiguration.java +++ b/java/src/main/java/org/eclipse/ditto/client/configuration/ClientCredentialsAuthenticationConfiguration.java @@ -42,16 +42,15 @@ public final class ClientCredentialsAuthenticationConfiguration extends Abstract private final List scopes; private final Duration expiryGracePeriod; - private ClientCredentialsAuthenticationConfiguration(final String tokenEndpoint, final String clientId, - final String clientSecret, final Collection scopes, final Duration expiryGracePeriod, - final Map additionalHeaders, - @Nullable final ProxyConfiguration proxyConfiguration) { - super(clientId, additionalHeaders, proxyConfiguration); - this.tokenEndpoint = checkNotNull(tokenEndpoint, "tokenEndpoint"); - this.clientId = checkNotNull(clientId, "clientId"); - this.clientSecret = checkNotNull(clientSecret, "clientSecret"); - this.scopes = Collections.unmodifiableList(new ArrayList<>(scopes)); - this.expiryGracePeriod = checkNotNull(expiryGracePeriod, "expiryGracePeriod"); + public ClientCredentialsAuthenticationConfiguration( + final ClientCredentialsAuthenticationConfigurationBuilder builder) { + + super(builder.clientId, builder.additionalHeaders, builder.proxyConfiguration); + tokenEndpoint = checkNotNull(builder.tokenEndpoint, "tokenEndpoint"); + clientId = checkNotNull(builder.clientId, "clientId"); + clientSecret = checkNotNull(builder.clientSecret, "clientSecret"); + scopes = Collections.unmodifiableList(new ArrayList<>(builder.scopes)); + expiryGracePeriod = checkNotNull(builder.expiryGracePeriod, "expiryGracePeriod"); } /** @@ -143,19 +142,25 @@ public String toString() { } @NotThreadSafe - public static class ClientCredentialsAuthenticationConfigurationBuilder + public static final class ClientCredentialsAuthenticationConfigurationBuilder implements AuthenticationConfiguration.Builder { private static final Duration DEFAULT_EXPIRY_GRACE_PERIOD = Duration.ofSeconds(5); - private final Map additionalHeaders = new HashMap<>(); - private String tokenEndpoint; private String clientId; private String clientSecret; private Collection scopes; - private Duration expiryGracePeriod = DEFAULT_EXPIRY_GRACE_PERIOD; - private ProxyConfiguration proxyConfiguration; + private Duration expiryGracePeriod; + @Nullable private ProxyConfiguration proxyConfiguration; + private final Map additionalHeaders; + + private ClientCredentialsAuthenticationConfigurationBuilder() { + scopes = Collections.emptyList(); + expiryGracePeriod = DEFAULT_EXPIRY_GRACE_PERIOD; + proxyConfiguration = null; + additionalHeaders = new HashMap<>(); + } /** * Sets the endpoint to retrieve tokens. @@ -164,18 +169,18 @@ public static class ClientCredentialsAuthenticationConfigurationBuilder * @return this builder. */ public ClientCredentialsAuthenticationConfigurationBuilder tokenEndpoint(final String tokenEndpoint) { - this.tokenEndpoint = tokenEndpoint; + this.tokenEndpoint = checkNotNull(tokenEndpoint, "tokenEndpoint"); return this; } /** - * Sets the client id to authenticate. + * Sets the client ID to authenticate. * - * @param clientId the client id. + * @param clientId the client ID. * @return this builder. */ public ClientCredentialsAuthenticationConfigurationBuilder clientId(final String clientId) { - this.clientId = clientId; + this.clientId = checkNotNull(clientId, "clientId"); return this; } @@ -187,7 +192,7 @@ public ClientCredentialsAuthenticationConfigurationBuilder clientId(final String * @return this builder. */ public ClientCredentialsAuthenticationConfigurationBuilder clientSecret(final String clientSecret) { - this.clientSecret = clientSecret; + this.clientSecret = checkNotNull(clientSecret, "clientSecret"); return this; } @@ -198,7 +203,7 @@ public ClientCredentialsAuthenticationConfigurationBuilder clientSecret(final St * @return this builder. */ public ClientCredentialsAuthenticationConfigurationBuilder scopes(final Collection scopes) { - this.scopes = scopes; + this.scopes = new ArrayList<>(checkNotNull(scopes, "scopes")); return this; } @@ -209,28 +214,29 @@ public ClientCredentialsAuthenticationConfigurationBuilder scopes(final Collecti * @return this builder. */ public ClientCredentialsAuthenticationConfigurationBuilder expiryGracePeriod(final Duration expiryGracePeriod) { - this.expiryGracePeriod = expiryGracePeriod; + this.expiryGracePeriod = checkNotNull(expiryGracePeriod, "expiryGracePeriod"); return this; } @Override public ClientCredentialsAuthenticationConfigurationBuilder withAdditionalHeader(final String key, final String value) { + additionalHeaders.put(checkNotNull(key, "key"), value); return this; } @Override public ClientCredentialsAuthenticationConfigurationBuilder proxyConfiguration( - final ProxyConfiguration proxyConfiguration) { - this.proxyConfiguration = checkNotNull(proxyConfiguration, "proxyConfiguration"); + @Nullable final ProxyConfiguration proxyConfiguration) { + + this.proxyConfiguration = proxyConfiguration; return this; } @Override public ClientCredentialsAuthenticationConfiguration build() { - return new ClientCredentialsAuthenticationConfiguration(tokenEndpoint, clientId, clientSecret, scopes, - expiryGracePeriod, additionalHeaders, proxyConfiguration); + return new ClientCredentialsAuthenticationConfiguration(this); } } diff --git a/java/src/main/java/org/eclipse/ditto/client/configuration/MessagingConfiguration.java b/java/src/main/java/org/eclipse/ditto/client/configuration/MessagingConfiguration.java index 5cc1a99c..51226eb9 100755 --- a/java/src/main/java/org/eclipse/ditto/client/configuration/MessagingConfiguration.java +++ b/java/src/main/java/org/eclipse/ditto/client/configuration/MessagingConfiguration.java @@ -15,6 +15,8 @@ import java.net.URI; import java.util.Optional; +import javax.annotation.Nullable; + import org.eclipse.ditto.model.base.json.JsonSchemaVersion; /** @@ -97,7 +99,7 @@ interface Builder { * @param proxyConfiguration the proxy configuration to set. * @return this builder. */ - Builder proxyConfiguration(ProxyConfiguration proxyConfiguration); + Builder proxyConfiguration(@Nullable ProxyConfiguration proxyConfiguration); /** * Sets the {@code trustStoreConfiguration}. diff --git a/java/src/main/java/org/eclipse/ditto/client/configuration/ProxyConfiguration.java b/java/src/main/java/org/eclipse/ditto/client/configuration/ProxyConfiguration.java index 6c15cee0..388a8aa0 100755 --- a/java/src/main/java/org/eclipse/ditto/client/configuration/ProxyConfiguration.java +++ b/java/src/main/java/org/eclipse/ditto/client/configuration/ProxyConfiguration.java @@ -12,7 +12,7 @@ */ package org.eclipse.ditto.client.configuration; -import static java.util.Objects.requireNonNull; +import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; import java.util.Optional; @@ -30,12 +30,11 @@ public final class ProxyConfiguration { @Nullable private final String username; @Nullable private final String password; - private ProxyConfiguration(final String host, final int port, @Nullable final String username, - @Nullable final String password) { - this.host = host; - this.port = port; - this.username = username; - this.password = password; + public ProxyConfiguration(final Builder builder) { + host = checkNotNull(builder.host, "host"); + port = checkNotNull(builder.port, "port"); + username = builder.username; + password = builder.password; } /** @@ -112,7 +111,7 @@ public interface ProxyOptionalSettable extends ProxyConfigurationBuildable { * @param username the username for proxy authentication. * @return a builder object to set the password. */ - ProxyPasswordSettable proxyUsername(String username); + ProxyPasswordSettable proxyUsername(@Nullable String username); } @@ -125,7 +124,7 @@ public interface ProxyPasswordSettable extends ProxyConfigurationBuildable { * @param password the password for proxy authentication. * @return a builder object for optional proxy settings. */ - ProxyOptionalSettable proxyPassword(String password); + ProxyOptionalSettable proxyPassword(@Nullable String password); } public interface ProxyConfigurationBuildable { @@ -136,8 +135,8 @@ public interface ProxyConfigurationBuildable { ProxyConfiguration build(); } - private static final class Builder implements ProxyConfigurationBuilder, ProxyHostSettable, - ProxyPortSettable, ProxyOptionalSettable, ProxyPasswordSettable, ProxyConfigurationBuildable { + private static final class Builder implements ProxyConfigurationBuilder, ProxyHostSettable, ProxyPortSettable, + ProxyOptionalSettable, ProxyPasswordSettable, ProxyConfigurationBuildable { private String host; private int port; @@ -145,16 +144,15 @@ private static final class Builder implements ProxyConfigurationBuilder, ProxyHo private String password; private Builder() { - } - - @Override - public ProxyConfiguration build() { - return new ProxyConfiguration(host, port, username, password); + host = null; + port = 0; + username = null; + password = null; } @Override public ProxyPortSettable proxyHost(final String host) { - this.host = requireNonNull(host, "Proxy host must not be null."); + this.host = checkNotNull(host, "Proxy host must not be null."); return this; } @@ -168,16 +166,22 @@ public ProxyOptionalSettable proxyPort(final int port) { } @Override - public ProxyPasswordSettable proxyUsername(final String username) { - this.username = requireNonNull(username, "Proxy username must not be null."); + public ProxyPasswordSettable proxyUsername(@Nullable final String username) { + this.username = username; return this; } @Override - public ProxyOptionalSettable proxyPassword(final String password) { - this.password = requireNonNull(password, "Proxy password must not be null."); + public ProxyOptionalSettable proxyPassword(@Nullable final String password) { + this.password = password; return this; } + + @Override + public ProxyConfiguration build() { + return new ProxyConfiguration(this); + } + } } diff --git a/java/src/main/java/org/eclipse/ditto/client/configuration/WebSocketMessagingConfiguration.java b/java/src/main/java/org/eclipse/ditto/client/configuration/WebSocketMessagingConfiguration.java index 8e87e285..56a88cef 100755 --- a/java/src/main/java/org/eclipse/ditto/client/configuration/WebSocketMessagingConfiguration.java +++ b/java/src/main/java/org/eclipse/ditto/client/configuration/WebSocketMessagingConfiguration.java @@ -38,14 +38,14 @@ public final class WebSocketMessagingConfiguration implements MessagingConfigura @Nullable private final ProxyConfiguration proxyConfiguration; @Nullable private final TrustStoreConfiguration trustStoreConfiguration; - private WebSocketMessagingConfiguration(final JsonSchemaVersion jsonSchemaVersion, final URI endpointUri, - final boolean reconnectEnabled, @Nullable final ProxyConfiguration proxyConfiguration, - @Nullable final TrustStoreConfiguration trustStoreConfiguration) { - this.jsonSchemaVersion = jsonSchemaVersion; + public WebSocketMessagingConfiguration(final WebSocketMessagingConfigurationBuilder builder, + final URI endpointUri) { + + jsonSchemaVersion = builder.jsonSchemaVersion; + reconnectEnabled = builder.reconnectEnabled; + proxyConfiguration = builder.proxyConfiguration; + trustStoreConfiguration = builder.trustStoreConfiguration; this.endpointUri = endpointUri; - this.reconnectEnabled = reconnectEnabled; - this.proxyConfiguration = proxyConfiguration; - this.trustStoreConfiguration = trustStoreConfiguration; } public static MessagingConfiguration.Builder newBuilder() { @@ -82,11 +82,17 @@ private static final class WebSocketMessagingConfigurationBuilder implements Mes private static final List ALLOWED_URI_SCHEME = Arrays.asList("wss", "ws"); private static final String WS_PATH = "/ws/"; - private JsonSchemaVersion jsonSchemaVersion = JsonSchemaVersion.LATEST; + private JsonSchemaVersion jsonSchemaVersion; private URI endpointUri; - private boolean reconnectEnabled = true; - private ProxyConfiguration proxyConfiguration; + private boolean reconnectEnabled; + @Nullable private ProxyConfiguration proxyConfiguration; private TrustStoreConfiguration trustStoreConfiguration; + + private WebSocketMessagingConfigurationBuilder() { + jsonSchemaVersion = JsonSchemaVersion.LATEST; + reconnectEnabled = true; + proxyConfiguration = null; + } @Override public MessagingConfiguration.Builder jsonSchemaVersion(final JsonSchemaVersion jsonSchemaVersion) { @@ -103,7 +109,7 @@ public MessagingConfiguration.Builder endpoint(final String endpoint) { return MessageFormat.format(msgTemplate, uriScheme, ALLOWED_URI_SCHEME); }); - this.endpointUri = uri; + endpointUri = uri; return this; } @@ -115,7 +121,7 @@ public MessagingConfiguration.Builder reconnectEnabled(final boolean reconnectEn @Override public MessagingConfiguration.Builder proxyConfiguration(final ProxyConfiguration proxyConfiguration) { - this.proxyConfiguration = checkNotNull(proxyConfiguration, "proxyConfiguration"); + this.proxyConfiguration = proxyConfiguration; return this; } @@ -128,9 +134,8 @@ public MessagingConfiguration.Builder trustStoreConfiguration( @Override public MessagingConfiguration build() { - final URI wsEndpointUri = appendWsPath(this.endpointUri, jsonSchemaVersion); - return new WebSocketMessagingConfiguration(jsonSchemaVersion, wsEndpointUri, reconnectEnabled, - proxyConfiguration, trustStoreConfiguration); + final URI wsEndpointUri = appendWsPath(endpointUri, jsonSchemaVersion); + return new WebSocketMessagingConfiguration(this, wsEndpointUri); } private static URI appendWsPath(final URI baseUri, final JsonSchemaVersion schemaVersion) { diff --git a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java index 3535277c..46141cc2 100644 --- a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java +++ b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java @@ -462,8 +462,7 @@ private Adaptable tryToConvertToAdaptable(final Event event, final TopicPath. } } - private DittoHeaders adjustHeadersForLive(final WithDittoHeaders withDittoHeaders) { - + private static DittoHeaders adjustHeadersForLive(final WithDittoHeaders withDittoHeaders) { return withDittoHeaders.getDittoHeaders().toBuilder() .removeHeader(DittoHeaderDefinition.READ_SUBJECTS.getKey()) .removeHeader(DittoHeaderDefinition.AUTHORIZATION_CONTEXT.getKey()) @@ -473,7 +472,6 @@ private DittoHeaders adjustHeadersForLive(final WithDittoHeaders withDittoHea @Override public CompletableFuture sendAdaptable(final Adaptable adaptable) { - DittoHeaders headers = adaptable.getHeaders().orElseGet(DittoHeaders::empty); Adaptable adaptableToSend = adaptable; if (!headers.getCorrelationId().isPresent()) { @@ -527,18 +525,25 @@ public boolean registerMessageHandler(final String name, final Map Date: Mon, 23 Mar 2020 07:55:53 +0100 Subject: [PATCH 04/23] Issue eclipse/ditto#611: fixed assembly.xml after splitting up the "ditto-signals-acks" module in 2 Signed-off-by: Thomas Jaeckle --- java/src/main/assembly/assembly.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/src/main/assembly/assembly.xml b/java/src/main/assembly/assembly.xml index ff6e190c..68fae55b 100755 --- a/java/src/main/assembly/assembly.xml +++ b/java/src/main/assembly/assembly.xml @@ -39,7 +39,8 @@ org.eclipse.ditto:ditto-model-messages org.eclipse.ditto:ditto-model-things org.eclipse.ditto:ditto-signals-base - org.eclipse.ditto:ditto-signals-acks + org.eclipse.ditto:ditto-signals-acks-base + org.eclipse.ditto:ditto-signals-acks-things org.eclipse.ditto:ditto-signals-commands-base org.eclipse.ditto:ditto-signals-commands-things org.eclipse.ditto:ditto-signals-commands-policies From b83bf9a6a8d50703f7772caeb98f355d7426a089 Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Mon, 23 Mar 2020 08:45:17 +0100 Subject: [PATCH 05/23] Issue eclipse/ditto#611: excluded internal builder from api breakage check Signed-off-by: Thomas Jaeckle --- java/pom.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/pom.xml b/java/pom.xml index c532c64a..0c05462f 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -324,7 +324,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M1 + 3.0.0-M4 true @@ -339,7 +339,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.0.0-M1 + 3.0.0-M4 integration-test @@ -439,6 +439,8 @@ org.eclipse.ditto.client.messaging.internal org.eclipse.ditto.client.options.internal org.eclipse.ditto.client.twin.internal + + org.eclipse.ditto.client.configuration.ClientCredentialsAuthenticationConfiguration$ClientCredentialsAuthenticationConfigurationBuilder From bfb3ae57c9b2a48f4c61e30d2943c09f9dba5fc9 Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Fri, 27 Mar 2020 10:38:27 +0100 Subject: [PATCH 06/23] Issue eclipse/ditto#611: when "correlation-id" is set as additional header, use it in the local sessionId, otherwise send along the generated local session id as "correlation-id" header and therefore client session identifier Signed-off-by: Thomas Jaeckle --- .../AbstractAuthenticationConfiguration.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/configuration/AbstractAuthenticationConfiguration.java b/java/src/main/java/org/eclipse/ditto/client/configuration/AbstractAuthenticationConfiguration.java index e73e9e03..cbcac2e7 100644 --- a/java/src/main/java/org/eclipse/ditto/client/configuration/AbstractAuthenticationConfiguration.java +++ b/java/src/main/java/org/eclipse/ditto/client/configuration/AbstractAuthenticationConfiguration.java @@ -24,6 +24,8 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import org.eclipse.ditto.model.base.headers.DittoHeaderDefinition; + /** * Abstract implementation for common aspects of * {@link org.eclipse.ditto.client.configuration.AuthenticationConfiguration}. @@ -42,7 +44,14 @@ abstract class AbstractAuthenticationConfiguration implements AuthenticationConf checkNotNull(identifier, "identifier"); checkNotNull(additionalHeaders, "additionalHeaders"); - sessionId = identifier + ":" + UUID.randomUUID().toString(); + final String connectionCorrelationId; + if (additionalHeaders.containsKey(DittoHeaderDefinition.CORRELATION_ID.getKey())) { + connectionCorrelationId = additionalHeaders.get(DittoHeaderDefinition.CORRELATION_ID.getKey()); + } else { + connectionCorrelationId = UUID.randomUUID().toString(); + additionalHeaders.put(DittoHeaderDefinition.CORRELATION_ID.getKey(), connectionCorrelationId); + } + sessionId = identifier + ":" + connectionCorrelationId; this.additionalHeaders = Collections.unmodifiableMap(new HashMap<>(additionalHeaders)); this.proxyConfiguration = proxyConfiguration; } From 5fea1df75f1d47044f1bd75e1496db1cd38b8292 Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Tue, 31 Mar 2020 12:04:53 +0200 Subject: [PATCH 07/23] Issue eclipse/ditto#611: enhanced Ditto Java client by sending custom "acknowledgements" whenever processing "Changes" (which are created from subscribed ThingEvents) * enhanced Change by extending WithDittoHeaders * added a TODO to solve once the search is added to the Ditto Client in order to reduce merge conflicts Signed-off-by: Thomas Jaeckle --- .../changes/AcknowledgementRequestHandle.java | 75 ++++++++++ .../eclipse/ditto/client/changes/Change.java | 47 ++++++- ...ImmutableAcknowledgementRequestHandle.java | 131 ++++++++++++++++++ .../changes/internal/ImmutableChange.java | 95 +++++++++++-- .../internal/ImmutableFeatureChange.java | 73 ++++++++-- .../internal/ImmutableFeaturesChange.java | 73 ++++++++-- .../internal/ImmutableThingChange.java | 72 ++++++++-- .../client/internal/CommonManagementImpl.java | 33 ++--- .../client/internal/DefaultDittoClient.java | 84 +++++++---- .../internal/FeatureHandleImpl.java | 10 +- .../management/internal/ThingHandleImpl.java | 21 +-- .../client/messaging/MessagingProvider.java | 7 + .../internal/WebSocketMessagingProvider.java | 11 ++ ...tableAcknowledgementRequestHandleTest.java | 46 ++++++ .../changes/internal/ImmutableChangeTest.java | 18 +-- .../internal/ImmutableThingChangeTest.java | 17 ++- .../messaging/mock/MockMessagingProvider.java | 10 +- 17 files changed, 686 insertions(+), 137 deletions(-) create mode 100644 java/src/main/java/org/eclipse/ditto/client/changes/AcknowledgementRequestHandle.java create mode 100644 java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableAcknowledgementRequestHandle.java create mode 100644 java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableAcknowledgementRequestHandleTest.java diff --git a/java/src/main/java/org/eclipse/ditto/client/changes/AcknowledgementRequestHandle.java b/java/src/main/java/org/eclipse/ditto/client/changes/AcknowledgementRequestHandle.java new file mode 100644 index 00000000..07e87804 --- /dev/null +++ b/java/src/main/java/org/eclipse/ditto/client/changes/AcknowledgementRequestHandle.java @@ -0,0 +1,75 @@ +/* + * 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 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.client.changes; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; +import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.base.entity.id.EntityIdWithType; +import org.eclipse.ditto.model.base.headers.WithDittoHeaders; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; + +/** + * Abstraction for handling {@code AcknowledgementRequest}s issued by the Ditto backend together with e.g. + * {@code Event}s. This handle provides means to {@code acknowledge} such acknowledgement requests with a custom + * {@code HttpStatusCode}, an optional {@code payload} or - alternatively - with a self built {@code Acknowledgement}. + * + * @since 1.1.0 + */ +@Immutable +public interface AcknowledgementRequestHandle extends WithDittoHeaders { + + /** + * Returns the {@code AcknowledgementLabel} this handle was created for. + * + * @return the acknowledgement label to handle. + */ + AcknowledgementLabel getAcknowledgementLabel(); + + /** + * Returns the entity ID containing the entity type this handle was created for. + * + * @return the entity id to handle. + */ + EntityIdWithType getEntityId(); + + /** + * Builds and sends an {@code Acknowledgement} to the Ditto backend based on the information this handle instance + * already has, combined with the passed {@code statusCode} and no {@code payload}. + * + * @param statusCode the http status code to apply for the acknowledgement to send: use a range between 200 and 300 + * in order to declare a successful acknowledgement and a status code above 400 to declare a not successful one. + */ + void acknowledge(HttpStatusCode statusCode); + + /** + * Builds and sends an {@code Acknowledgement} to the Ditto backend based on the information this handle instance + * already has, combined with the passed {@code statusCode} and the passed {@code payload}. + * + * @param statusCode the http status code to apply for the acknowledgement to send: use a range between 200 and 300 + * in order to declare a successful acknowledgement and a status code above 400 to declare a not successful one. + * @param payload the payload as {@code JsonValue} to include in the sent acknowledgement. + */ + void acknowledge(HttpStatusCode statusCode, @Nullable JsonValue payload); + + /** + * Sends the passed {@code acknowledgement} to the Ditto backend. + * + * @param acknowledgement the already built {@code Acknowledgement} to send to the Ditto backend. + */ + void acknowledge(Acknowledgement acknowledgement); + +} diff --git a/java/src/main/java/org/eclipse/ditto/client/changes/Change.java b/java/src/main/java/org/eclipse/ditto/client/changes/Change.java index 637733ff..7d338bd1 100755 --- a/java/src/main/java/org/eclipse/ditto/client/changes/Change.java +++ b/java/src/main/java/org/eclipse/ditto/client/changes/Change.java @@ -13,13 +13,18 @@ package org.eclipse.ditto.client.changes; import java.time.Instant; +import java.util.Collection; import java.util.Optional; +import java.util.function.Consumer; import javax.annotation.Nullable; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; +import org.eclipse.ditto.model.base.entity.type.WithEntityType; +import org.eclipse.ditto.model.base.headers.WithDittoHeaders; import org.eclipse.ditto.signals.base.WithId; /** @@ -27,7 +32,7 @@ * * @since 1.0.0 */ -public interface Change extends WithId { +public interface Change extends WithId, WithEntityType, WithDittoHeaders { /** * Returns the {@link ChangeAction} which caused this change. @@ -88,8 +93,8 @@ default boolean isFull() { /** * Returns the extra information which enriches the actual value of this change. * - * @since 1.1.0 * @return the extra data or an empty Optional. + * @since 1.1.0 */ Optional getExtra(); @@ -97,10 +102,46 @@ default boolean isFull() { * Sets the given extra information which enriches the actual value of the change. * Previously set extra is replaced. * - * @since 1.1.0 * @param extra the extra data information or {@code null}. * @return a new instance of this change with the added {@code extra} data. + * @since 1.1.0 */ Change withExtra(@Nullable JsonObject extra); + /** + * Sets the given {@code path} and {@code value} into the change. + * + * @param path the relative path of the changed JSON field. + * @param value the optional value of the changed JSON field. + * @return a new instance of this change with the added data. + * @since 1.1.0 + */ + Change withPathAndValue(JsonPointer path, @Nullable JsonValue value); + + /** + * Handles {@code AcknowledgementRequest}s issued by the Ditto backend for a received event translated into this + * change by invoking the passed {@code acknowledgementHandles} consumer with client side + * {@code AcknowledgementHandle}s. + * + * @param acknowledgementHandles the consumer to invoke with a collection of {@code AcknowledgementHandle}s used to + * send back {@code Acknowledgements}. + * @since 1.1.0 + */ + void handleAcknowledgementRequests(Consumer> acknowledgementHandles); + + /** + * Handles an {@code AcknowledgementRequest} identified by the passed {@code acknowledgementLabel} issued by the + * Ditto backend for a received event translated into this change by invoking the passed + * {@code acknowledgementHandle} consumer with a client side {@code AcknowledgementHandle} - if the passed + * acknowledgementLabel was present in the requested acknowledgements. + * + * @param acknowledgementLabel the {@code AcknowledgementLabel} which should be handled - if present - by the passed + * {@code acknowledgementHandle}. + * @param acknowledgementHandle the consumer to invoke with a {@code AcknowledgementHandle} used to + * send back an {@code Acknowledgement}. + * @since 1.1.0 + */ + void handleAcknowledgementRequest(AcknowledgementLabel acknowledgementLabel, + Consumer acknowledgementHandle); + } diff --git a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableAcknowledgementRequestHandle.java b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableAcknowledgementRequestHandle.java new file mode 100644 index 00000000..9bc13228 --- /dev/null +++ b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableAcknowledgementRequestHandle.java @@ -0,0 +1,131 @@ +/* + * 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 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.client.changes.internal; + +import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; + +import java.util.Objects; +import java.util.function.Consumer; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +import org.eclipse.ditto.client.changes.AcknowledgementRequestHandle; +import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; +import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.base.entity.id.EntityIdWithType; +import org.eclipse.ditto.model.base.headers.DittoHeaders; +import org.eclipse.ditto.model.base.headers.DittoHeadersBuilder; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; + +/** + * An immutable implementation of {@link AcknowledgementRequestHandle}. + * + * @since 1.1.0 + */ +@Immutable +final class ImmutableAcknowledgementRequestHandle implements AcknowledgementRequestHandle { + + private final AcknowledgementLabel acknowledgementLabel; + private final EntityIdWithType entityId; + private final DittoHeaders dittoHeaders; + private final Consumer acknowledgementPublisher; + + /** + * Creates a new ImmutableAcknowledgementRequestHandle instance. + * + * @param acknowledgementLabel the acknowledgement label to handle. + * @param entityId the entity id to handle. + * @param dittoHeaders the ditto headers which were contained in the acknowledgement request to handle. + * @param acknowledgementPublisher the consumer for publishing built acknowledgements to the Ditto backend. + */ + ImmutableAcknowledgementRequestHandle(final AcknowledgementLabel acknowledgementLabel, + final EntityIdWithType entityId, + final DittoHeaders dittoHeaders, + final Consumer acknowledgementPublisher) { + + this.acknowledgementLabel = checkNotNull(acknowledgementLabel, "acknowledgementLabel"); + this.entityId = checkNotNull(entityId, "entityId"); + this.dittoHeaders = checkNotNull(dittoHeaders, "dittoHeaders"); + this.acknowledgementPublisher = checkNotNull(acknowledgementPublisher, "acknowledgementPublisher"); + } + + @Override + public AcknowledgementLabel getAcknowledgementLabel() { + return acknowledgementLabel; + } + + @Override + public EntityIdWithType getEntityId() { + return entityId; + } + + @Override + public DittoHeaders getDittoHeaders() { + return dittoHeaders; + } + + @Override + public AcknowledgementRequestHandle setDittoHeaders(final DittoHeaders dittoHeaders) { + return new ImmutableAcknowledgementRequestHandle(acknowledgementLabel, entityId, dittoHeaders, + acknowledgementPublisher); + } + + @Override + public void acknowledge(final HttpStatusCode statusCode) { + acknowledge(statusCode, null); + } + + @Override + public void acknowledge(final HttpStatusCode statusCode, @Nullable final JsonValue payload) { + // only retain the bare minimum of received DittoHeaders by default: + final DittoHeadersBuilder dittoHeadersBuilder = DittoHeaders.newBuilder(); + dittoHeaders.getCorrelationId().ifPresent(dittoHeadersBuilder::correlationId); + final DittoHeaders minimizedDittoHeaders = dittoHeadersBuilder.build(); + acknowledge(Acknowledgement.of(acknowledgementLabel, entityId, statusCode, minimizedDittoHeaders, payload)); + } + + @Override + public void acknowledge(final Acknowledgement acknowledgement) { + acknowledgementPublisher.accept(acknowledgement); + } + + @Override + public boolean equals(@Nullable final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ImmutableAcknowledgementRequestHandle that = (ImmutableAcknowledgementRequestHandle) o; + return Objects.equals(acknowledgementLabel, that.acknowledgementLabel) && + Objects.equals(entityId, that.entityId) && + Objects.equals(dittoHeaders, that.dittoHeaders); + } + + @Override + public int hashCode() { + return Objects.hash(acknowledgementLabel, entityId, dittoHeaders); + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [" + + "acknowledgementLabel=" + acknowledgementLabel + + ", entityId=" + entityId + + ", dittoHeaders=" + dittoHeaders + + "]"; + } +} diff --git a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableChange.java b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableChange.java index de6352c3..d16d044b 100644 --- a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableChange.java +++ b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableChange.java @@ -12,21 +12,31 @@ */ package org.eclipse.ditto.client.changes.internal; -import static org.eclipse.ditto.model.base.common.ConditionChecker.argumentNotNull; +import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; import java.time.Instant; +import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; +import java.util.stream.Collectors; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import org.eclipse.ditto.client.changes.AcknowledgementRequestHandle; import org.eclipse.ditto.client.changes.Change; import org.eclipse.ditto.client.changes.ChangeAction; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; import org.eclipse.ditto.model.base.entity.id.EntityId; +import org.eclipse.ditto.model.base.entity.id.EntityIdWithType; +import org.eclipse.ditto.model.base.entity.type.EntityType; +import org.eclipse.ditto.model.base.headers.DittoHeaders; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; /** * An immutable holder for an {@link org.eclipse.ditto.model.base.entity.id.EntityId} and a {@link ChangeAction}. @@ -37,40 +47,49 @@ @Immutable public final class ImmutableChange implements Change { - private final EntityId entityId; + private final EntityIdWithType entityId; private final ChangeAction action; private final JsonPointer path; @Nullable private final JsonValue value; private final long revision; @Nullable private final Instant timestamp; @Nullable private final JsonObject extra; + private final DittoHeaders dittoHeaders; + private final Consumer acknowledgementPublisher; /** * Constructs a new {@code ImmutableChange} object. * - * @param entityId ID of the changed entity. + * @param entityId ID (with EntityType) of the changed entity. * @param changeAction the operation which caused the change. * @param path the JsonPointer of the changed json field. * @param value the value of the changed json field. * @param revision the revision (change counter) of the change. * @param timestamp the timestamp of the change. * @param extra the extra data to be included in the change. + * @param dittoHeaders the DittoHeaders of the event which lead to the change. + * @param acknowledgementPublisher the consumer for publishing built acknowledgements to the Ditto backend. + * @throws NullPointerException if any required argument is {@code null}. */ - public ImmutableChange(final EntityId entityId, + public ImmutableChange(final EntityIdWithType entityId, final ChangeAction changeAction, final JsonPointer path, @Nullable final JsonValue value, final long revision, @Nullable final Instant timestamp, - @Nullable final JsonObject extra) { + @Nullable final JsonObject extra, + final DittoHeaders dittoHeaders, + final Consumer acknowledgementPublisher) { - this.entityId = argumentNotNull(entityId, "entityId"); - this.action = argumentNotNull(changeAction, "changeAction"); - this.path = argumentNotNull(path, "path"); + this.entityId = checkNotNull(entityId, "entityId"); + this.action = checkNotNull(changeAction, "changeAction"); + this.path = checkNotNull(path, "path"); this.value = value; this.revision = revision; this.timestamp = timestamp; this.extra = extra; + this.dittoHeaders = checkNotNull(dittoHeaders, "dittoHeaders"); + this.acknowledgementPublisher = checkNotNull(acknowledgementPublisher, "acknowledgementPublisher"); } @Override @@ -78,6 +97,11 @@ public EntityId getEntityId() { return entityId; } + @Override + public EntityType getEntityType() { + return entityId.getEntityType(); + } + @Override public ChangeAction getAction() { return action; @@ -110,11 +134,54 @@ public Optional getExtra() { @Override public Change withExtra(@Nullable final JsonObject extra) { - return new ImmutableChange(entityId, action, path, value, revision, timestamp, extra); + return new ImmutableChange(entityId, action, path, value, revision, timestamp, extra, dittoHeaders, + acknowledgementPublisher); + } + + @Override + public DittoHeaders getDittoHeaders() { + return dittoHeaders; + } + + @Override + public Change setDittoHeaders(final DittoHeaders dittoHeaders) { + return new ImmutableChange(entityId, action, path, value, revision, timestamp, extra, dittoHeaders, + acknowledgementPublisher); + } + + @Override + public void handleAcknowledgementRequests(final Consumer> acknowledgementHandles) { + + checkNotNull(acknowledgementHandles, "handleConsumers"); + acknowledgementHandles.accept( + getDittoHeaders().getAcknowledgementRequests().stream() + .map(request -> new ImmutableAcknowledgementRequestHandle(request.getLabel(), entityId, dittoHeaders, + acknowledgementPublisher)) + .collect(Collectors.toCollection(LinkedHashSet::new)) + ); + } + + @Override + public Change withPathAndValue(final JsonPointer path, @Nullable final JsonValue value) { + return new ImmutableChange(entityId, action, path, value, revision, timestamp, extra, dittoHeaders, + acknowledgementPublisher); + } + + @Override + public void handleAcknowledgementRequest(final AcknowledgementLabel acknowledgementLabel, + final Consumer acknowledgementHandle) { + + checkNotNull(acknowledgementLabel, "acknowledgementLabel"); + checkNotNull(acknowledgementHandle, "handleConsumer"); + getDittoHeaders().getAcknowledgementRequests().stream() + .filter(req -> req.getLabel().equals(acknowledgementLabel)) + .map(request -> new ImmutableAcknowledgementRequestHandle(request.getLabel(), entityId, dittoHeaders, + acknowledgementPublisher)) + .forEach(acknowledgementHandle); } @Override - public boolean equals(final Object o) { + public boolean equals(@Nullable final Object o) { if (this == o) { return true; } @@ -127,13 +194,14 @@ public boolean equals(final Object o) { Objects.equals(path, that.path) && Objects.equals(value, that.value) && revision == that.revision && - Objects.equals(timestamp, that.timestamp)&& - Objects.equals(extra, that.extra); + Objects.equals(timestamp, that.timestamp) && + Objects.equals(extra, that.extra) && + Objects.equals(dittoHeaders, that.dittoHeaders); } @Override public int hashCode() { - return Objects.hash(entityId, action, path, value, revision, timestamp, extra); + return Objects.hash(entityId, action, path, value, revision, timestamp, extra, dittoHeaders); } @Override @@ -146,6 +214,7 @@ public String toString() { ", revision=" + revision + ", timestamp=" + timestamp + ", extra=" + extra + + ", dittoHeaders=" + dittoHeaders + "]"; } diff --git a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableFeatureChange.java b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableFeatureChange.java index d0f2344b..0a278386 100644 --- a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableFeatureChange.java +++ b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableFeatureChange.java @@ -12,21 +12,31 @@ */ package org.eclipse.ditto.client.changes.internal; +import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; + import java.time.Instant; +import java.util.Collection; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import org.eclipse.ditto.client.changes.AcknowledgementRequestHandle; import org.eclipse.ditto.client.changes.Change; import org.eclipse.ditto.client.changes.ChangeAction; import org.eclipse.ditto.client.changes.FeatureChange; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; import org.eclipse.ditto.model.base.entity.id.EntityId; +import org.eclipse.ditto.model.base.entity.id.EntityIdWithType; +import org.eclipse.ditto.model.base.entity.type.EntityType; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.things.Feature; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; /** * An immutable implementation of {@link org.eclipse.ditto.client.changes.FeatureChange}. @@ -49,18 +59,35 @@ public final class ImmutableFeatureChange implements FeatureChange { * @param revision the revision (change counter) of the change. * @param timestamp the timestamp of the change. * @param extra the extra data to be included in the change. - * @throws IllegalArgumentException if any argument is {@code null}. + * @param dittoHeaders the DittoHeaders of the event which lead to the change. + * @param acknowledgementPublisher the consumer for publishing built acknowledgements to the Ditto backend. + * @throws NullPointerException if any required argument is {@code null}. */ - public ImmutableFeatureChange(final EntityId entityId, + public ImmutableFeatureChange(final EntityIdWithType entityId, final ChangeAction changeAction, @Nullable final Feature feature, final JsonPointer path, final long revision, @Nullable final Instant timestamp, - @Nullable final JsonObject extra) { + @Nullable final JsonObject extra, + final DittoHeaders dittoHeaders, + final Consumer acknowledgementPublisher) { this(new ImmutableChange(entityId, changeAction, path, getJsonValueForFeature(feature), revision, timestamp, - extra), feature); + extra, dittoHeaders, acknowledgementPublisher), feature); + } + + /** + * Constructs a new {@code ImmutableFeatureChange} object. + * + * @param change the change to use for delegation. + * @param feature the additional {@code Feature} this FeatureChange is aware of. + * @throws NullPointerException if {@code change} is {@code null}. + * @since 1.1.0 + */ + public ImmutableFeatureChange(final Change change, @Nullable final Feature feature) { + this.change = checkNotNull(change, "change"); + this.feature = feature; } @Nullable @@ -68,16 +95,16 @@ private static JsonValue getJsonValueForFeature(@Nullable final Feature feature) return null != feature ? feature.toJson(feature.getImplementedSchemaVersion()) : null; } - private ImmutableFeatureChange(final Change delegationTarget, @Nullable final Feature feature) { - change = delegationTarget; - this.feature = feature; - } - @Override public EntityId getEntityId() { return change.getEntityId(); } + @Override + public EntityType getEntityType() { + return change.getEntityType(); + } + @Override public ChangeAction getAction() { return change.getAction(); @@ -119,7 +146,33 @@ public ImmutableFeatureChange withExtra(@Nullable final JsonObject extra) { } @Override - public boolean equals(final Object o) { + public DittoHeaders getDittoHeaders() { + return change.getDittoHeaders(); + } + + @Override + public Change setDittoHeaders(final DittoHeaders dittoHeaders) { + return new ImmutableFeatureChange(change.setDittoHeaders(dittoHeaders), feature); + } + + @Override + public void handleAcknowledgementRequests(final Consumer> acknowledgementHandles) { + change.handleAcknowledgementRequests(acknowledgementHandles); + } + + @Override + public Change withPathAndValue(final JsonPointer path, @Nullable final JsonValue value) { + return new ImmutableFeatureChange(change.withPathAndValue(path, value), feature); + } + + @Override + public void handleAcknowledgementRequest(final AcknowledgementLabel acknowledgementLabel, + final Consumer acknowledgementHandle) { + change.handleAcknowledgementRequest(acknowledgementLabel, acknowledgementHandle); + } + + @Override + public boolean equals(@Nullable final Object o) { if (this == o) { return true; } diff --git a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableFeaturesChange.java b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableFeaturesChange.java index 16542379..dc1d6863 100644 --- a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableFeaturesChange.java +++ b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableFeaturesChange.java @@ -12,21 +12,31 @@ */ package org.eclipse.ditto.client.changes.internal; +import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; + import java.time.Instant; +import java.util.Collection; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import org.eclipse.ditto.client.changes.AcknowledgementRequestHandle; import org.eclipse.ditto.client.changes.Change; import org.eclipse.ditto.client.changes.ChangeAction; import org.eclipse.ditto.client.changes.FeaturesChange; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; import org.eclipse.ditto.model.base.entity.id.EntityId; +import org.eclipse.ditto.model.base.entity.id.EntityIdWithType; +import org.eclipse.ditto.model.base.entity.type.EntityType; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.things.Features; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; /** * An immutable implementation of {@link org.eclipse.ditto.client.changes.FeaturesChange}. @@ -49,18 +59,35 @@ public final class ImmutableFeaturesChange implements FeaturesChange { * @param revision the revision (change counter) of the change. * @param timestamp the timestamp of the change. * @param extra the extra data to be included in the change. - * @throws IllegalArgumentException if any argument is {@code null}. + * @param dittoHeaders the DittoHeaders of the event which lead to the change. + * @param acknowledgementPublisher the consumer for publishing built acknowledgements to the Ditto backend. + * @throws NullPointerException if any required argument is {@code null}. */ - public ImmutableFeaturesChange(final EntityId entityId, + public ImmutableFeaturesChange(final EntityIdWithType entityId, final ChangeAction changeAction, @Nullable final Features features, final JsonPointer path, final long revision, @Nullable final Instant timestamp, - @Nullable final JsonObject extra) { + @Nullable final JsonObject extra, + final DittoHeaders dittoHeaders, + final Consumer acknowledgementPublisher) { this(new ImmutableChange(entityId, changeAction, path, getJsonValueForFeatures(features), revision, timestamp, - extra), features); + extra, dittoHeaders, acknowledgementPublisher), features); + } + + /** + * Constructs a new {@code ImmutableFeaturesChange} object. + * + * @param change the change to use for delegation. + * @param features the additional {@code Features} this FeaturesChange is aware of. + * @throws NullPointerException if {@code change} is {@code null}. + * @since 1.1.0 + */ + public ImmutableFeaturesChange(final Change change, @Nullable final Features features) { + this.change = checkNotNull(change, "change"); + this.features = features; } @Nullable @@ -68,16 +95,16 @@ private static JsonValue getJsonValueForFeatures(@Nullable final Features featur return null != features ? features.toJson(features.getImplementedSchemaVersion()) : null; } - private ImmutableFeaturesChange(final Change delegationTarget, @Nullable final Features features) { - change = delegationTarget; - this.features = features; - } - @Override public EntityId getEntityId() { return change.getEntityId(); } + @Override + public EntityType getEntityType() { + return change.getEntityType(); + } + @Override public ChangeAction getAction() { return change.getAction(); @@ -119,7 +146,33 @@ public Change withExtra(@Nullable final JsonObject extra) { } @Override - public boolean equals(final Object o) { + public DittoHeaders getDittoHeaders() { + return change.getDittoHeaders(); + } + + @Override + public Change setDittoHeaders(final DittoHeaders dittoHeaders) { + return new ImmutableFeaturesChange(change.setDittoHeaders(dittoHeaders), features); + } + + @Override + public Change withPathAndValue(final JsonPointer path, @Nullable final JsonValue value) { + return new ImmutableFeaturesChange(change.withPathAndValue(path, value), features); + } + + @Override + public void handleAcknowledgementRequests(final Consumer> acknowledgementHandles) { + change.handleAcknowledgementRequests(acknowledgementHandles); + } + + @Override + public void handleAcknowledgementRequest(final AcknowledgementLabel acknowledgementLabel, + final Consumer acknowledgementHandle) { + change.handleAcknowledgementRequest(acknowledgementLabel, acknowledgementHandle); + } + + @Override + public boolean equals(@Nullable final Object o) { if (this == o) { return true; } diff --git a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableThingChange.java b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableThingChange.java index b10c4552..e125e23b 100644 --- a/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableThingChange.java +++ b/java/src/main/java/org/eclipse/ditto/client/changes/internal/ImmutableThingChange.java @@ -15,12 +15,15 @@ import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; import java.time.Instant; +import java.util.Collection; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import org.eclipse.ditto.client.changes.AcknowledgementRequestHandle; import org.eclipse.ditto.client.changes.Change; import org.eclipse.ditto.client.changes.ChangeAction; import org.eclipse.ditto.client.changes.ThingChange; @@ -28,9 +31,14 @@ import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; import org.eclipse.ditto.model.base.entity.id.EntityId; +import org.eclipse.ditto.model.base.entity.id.EntityIdWithType; +import org.eclipse.ditto.model.base.entity.type.EntityType; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.things.Thing; import org.eclipse.ditto.model.things.ThingId; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; /** * Immutable implementation for {@link org.eclipse.ditto.client.changes.ThingChange}. @@ -54,18 +62,22 @@ public final class ImmutableThingChange implements ThingChange { * @param revision the revision (change counter) of the change. * @param timestamp the timestamp of the change. * @param extra the extra data to be included in the change. + * @param dittoHeaders the DittoHeaders of the event which lead to the change. + * @param acknowledgementPublisher the consumer for publishing built acknowledgements to the Ditto backend. * @throws NullPointerException if any required argument is {@code null}. */ - public ImmutableThingChange(final EntityId entityId, + public ImmutableThingChange(final EntityIdWithType entityId, final ChangeAction changeAction, @Nullable final Thing thing, final JsonPointer path, final long revision, @Nullable final Instant timestamp, - @Nullable final JsonObject extra) { + @Nullable final JsonObject extra, + final DittoHeaders dittoHeaders, + final Consumer acknowledgementPublisher) { this(new ImmutableChange(checkNotNull(entityId, "Thing ID"), checkNotNull(changeAction, "change action"), path, - getJsonValueForThing(thing), revision, timestamp, extra), thing); + getJsonValueForThing(thing), revision, timestamp, extra, dittoHeaders, acknowledgementPublisher), thing); } @Nullable @@ -82,6 +94,8 @@ private static JsonValue getJsonValueForThing(@Nullable final Thing thing) { * deleted. * @param revision the revision (change counter) of the change. * @param timestamp the timestamp of the change. + * @param dittoHeaders the DittoHeaders of the event which lead to the change. + * @param acknowledgementPublisher the consumer for publishing built acknowledgements to the Ditto backend. * @throws NullPointerException if any required argument is {@code null}. */ public ImmutableThingChange(final ThingId thingId, @@ -89,13 +103,24 @@ public ImmutableThingChange(final ThingId thingId, @Nullable final Thing thing, final long revision, @Nullable final Instant timestamp, - @Nullable final JsonObject extra) { + @Nullable final JsonObject extra, + final DittoHeaders dittoHeaders, + final Consumer acknowledgementPublisher) { - this(thingId, changeAction, thing, JsonFactory.emptyPointer(), revision, timestamp, extra); + this(thingId, changeAction, thing, JsonFactory.emptyPointer(), revision, timestamp, extra, dittoHeaders, + acknowledgementPublisher); } - private ImmutableThingChange(final Change delegationTarget, @Nullable final Thing thing) { - change = delegationTarget; + /** + * Constructs a new {@code ImmutableThingChange} object. + * + * @param change the change to use for delegation. + * @param thing the additional {@code Thing} this ThingChange is aware of. + * @throws NullPointerException if {@code change} is {@code null}. + * @since 1.1.0 + */ + public ImmutableThingChange(final Change change, @Nullable final Thing thing) { + this.change = checkNotNull(change, "change"); this.thing = thing; } @@ -104,6 +129,11 @@ public EntityId getEntityId() { return change.getEntityId(); } + @Override + public EntityType getEntityType() { + return change.getEntityType(); + } + @Override public ChangeAction getAction() { return change.getAction(); @@ -144,13 +174,39 @@ public ImmutableThingChange withExtra(@Nullable final JsonObject extra) { return new ImmutableThingChange(change.withExtra(extra), thing); } + @Override + public DittoHeaders getDittoHeaders() { + return change.getDittoHeaders(); + } + + @Override + public Change setDittoHeaders(final DittoHeaders dittoHeaders) { + return new ImmutableThingChange(change.setDittoHeaders(dittoHeaders), thing); + } + + @Override + public Change withPathAndValue(final JsonPointer path, @Nullable final JsonValue value) { + return new ImmutableThingChange(change.withPathAndValue(path, value), thing); + } + + @Override + public void handleAcknowledgementRequests(final Consumer> acknowledgementHandles) { + change.handleAcknowledgementRequests(acknowledgementHandles); + } + + @Override + public void handleAcknowledgementRequest(final AcknowledgementLabel acknowledgementLabel, + final Consumer acknowledgementHandle) { + change.handleAcknowledgementRequest(acknowledgementLabel, acknowledgementHandle); + } + @Override public int hashCode() { return Objects.hash(change, thing); } @Override - public boolean equals(final Object obj) { + public boolean equals(@Nullable final Object obj) { if (this == obj) { return true; } diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java index 488b7719..ce5452a3 100755 --- a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java @@ -34,7 +34,6 @@ import org.eclipse.ditto.client.changes.FeatureChange; import org.eclipse.ditto.client.changes.FeaturesChange; import org.eclipse.ditto.client.changes.ThingChange; -import org.eclipse.ditto.client.changes.internal.ImmutableChange; import org.eclipse.ditto.client.changes.internal.ImmutableFeatureChange; import org.eclipse.ditto.client.changes.internal.ImmutableFeaturesChange; import org.eclipse.ditto.client.changes.internal.ImmutableThingChange; @@ -520,9 +519,7 @@ public void registerForAttributesChanges(final String registrationId, final Cons argumentNotNull(handler); SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/'{thingId}'/attributes"), - Change.class, handler, - (change, value, path, params) -> new ImmutableChange(change.getEntityId(), change.getAction(), path, - value, change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)) + Change.class, handler, (change, value, path, params) -> change.withPathAndValue(path, value) ); } @@ -534,9 +531,7 @@ public void registerForAttributeChanges(final String registrationId, final JsonP argumentNotNull(handler); SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/'{thingId}'/attributes{0}", attrPath), Change.class, - handler, - (change, value, path, params) -> new ImmutableChange(change.getEntityId(), change.getAction(), path, - value, change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)) + handler, (change, value, path, params) -> change.withPathAndValue(path, value) ); } @@ -545,14 +540,12 @@ public void registerForFeatureChanges(final String registrationId, final Consume argumentNotNull(handler); SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/'{thingId}'/features/'{featureId}'"), - FeatureChange.class, handler, - (change, value, path, params) -> { + FeatureChange.class, handler, (change, value, path, params) -> { final Feature feature = value != null ? ThingsModelFactory.newFeatureBuilder(value.asObject()) .useId(params.get("{featureId}")) .build() : null; - return new ImmutableFeatureChange(change.getEntityId(), change.getAction(), feature, path, - change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)); + return new ImmutableFeatureChange(change.withPathAndValue(path, value), feature); }); } @@ -567,8 +560,7 @@ public void registerForFeatureChanges(final String registrationId, final String FeatureChange.class, handler, (change, value, path, params) -> { final Feature feature = value != null ? ThingsModelFactory.newFeatureBuilder(value.asObject()).useId(featureId).build() : null; - return new ImmutableFeatureChange(change.getEntityId(), change.getAction(), feature, path, - change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)); + return new ImmutableFeatureChange(change.withPathAndValue(path, value), feature); }); } @@ -579,8 +571,7 @@ public void registerForFeaturesChanges(final String registrationId, final Consum SelectorUtil.formatJsonPointer(LOGGER, "/things/'{thingId}'/features"), FeaturesChange.class, handler, (change, value, path, params) -> { final Features features = value != null ? ThingsModelFactory.newFeatures(value.asObject()) : null; - return new ImmutableFeaturesChange(change.getEntityId(), change.getAction(), features, path, - change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)); + return new ImmutableFeaturesChange(change.withPathAndValue(path, value), features); }); } @@ -592,10 +583,7 @@ public void registerForFeaturePropertyChanges(final String registrationId, final argumentNotNull(handler); SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/'{thingId}'/features/{0}/properties", featureId), - Change.class, - handler, - (change, value, path, params) -> new ImmutableChange(change.getEntityId(), change.getAction(), path, - value, change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)) + Change.class, handler, (change, value, path, params) -> change.withPathAndValue(path, value) ); } @@ -611,9 +599,7 @@ public void registerForFeaturePropertyChanges(final String registrationId, SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/'{thingId}'/features/{0}/properties{1}", featureId, propertyPath), - Change.class, handler, - (change, value, path, params) -> new ImmutableChange(change.getEntityId(), change.getAction(), path, - value, change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)) + Change.class, handler, (change, value, path, params) -> change.withPathAndValue(path, value) ); } @@ -624,8 +610,7 @@ public void registerForThingChanges(final String registrationId, final Consumer< SelectorUtil.formatJsonPointer(LOGGER, "/things/'{thingId}'"), ThingChange.class, handler, (change, value, path, params) -> { final Thing thing = null != value ? ThingsModelFactory.newThing(value.asObject()) : null; - return new ImmutableThingChange(change.getEntityId(), change.getAction(), thing, path, - change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)); + return new ImmutableThingChange(change.withPathAndValue(path, value), thing); }); } diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/DefaultDittoClient.java b/java/src/main/java/org/eclipse/ditto/client/internal/DefaultDittoClient.java index 7c14cfcb..b5bd0291 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/DefaultDittoClient.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/DefaultDittoClient.java @@ -216,7 +216,8 @@ private static PoliciesImpl configurePolicyClient(final MessagingProvider messag return PoliciesImpl.newInstance(messagingProvider, responseForwarder, messageFactory, bus); } - private static OutgoingMessageFactory getOutgoingMessageFactoryForPolicies(final MessagingProvider messagingProvider) { + private static OutgoingMessageFactory getOutgoingMessageFactoryForPolicies( + final MessagingProvider messagingProvider) { final JsonSchemaVersion schemaVersion = messagingProvider.getMessagingConfiguration().getJsonSchemaVersion(); if (JsonSchemaVersion.V_1.equals(schemaVersion)) { LOGGER.warn("The MessagingProvider was configured with JsonSchemaVersion V_1 which is invalid for policy" + @@ -231,7 +232,7 @@ private static OutgoingMessageFactory getOutgoingMessageFactoryForPolicies(final private static void init(final PointerBus bus, final MessagingProvider messagingProvider, final ResponseForwarder responseForwarder) { registerKeyBasedDistributorForIncomingEvents(bus); - registerKeyBasedHandlersForIncomingEvents(bus); + registerKeyBasedHandlersForIncomingEvents(bus, messagingProvider); messagingProvider.registerReplyHandler(responseForwarder::handle); messagingProvider.initialize(); } @@ -261,26 +262,31 @@ private static void registerKeyBasedDistributorForIncomingEvents(final PointerBu }); } - private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus bus) { + private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus bus, + final MessagingProvider messagingProvider) { + /* * Thing */ SelectorUtil.addHandlerForThingEvent(LOGGER, bus, ThingCreated.TYPE, ThingCreated.class, e -> MessageFormat.format(THING_PATTERN, e.getThingEntityId()), (e, extra) -> new ImmutableThingChange(e.getThingEntityId(), ChangeAction.CREATED, e.getThing(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, ThingModified.TYPE, ThingModified.class, e -> MessageFormat.format(THING_PATTERN, e.getThingEntityId()), (e, extra) -> new ImmutableThingChange(e.getThingEntityId(), ChangeAction.UPDATED, e.getThing(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, ThingDeleted.TYPE, ThingDeleted.class, e -> MessageFormat.format(THING_PATTERN, e.getThingEntityId()), (e, extra) -> new ImmutableThingChange(e.getThingEntityId(), ChangeAction.DELETED, null, - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); /* @@ -292,7 +298,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.UPDATED, JsonPointer.empty(), e.getAccessControlList().toJson(e.getImplementedSchemaVersion()), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AclEntryCreated.TYPE, AclEntryCreated.class, @@ -301,7 +308,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.CREATED, JsonPointer.empty(), e.getAclEntry().toJson(e.getImplementedSchemaVersion()), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AclEntryModified.TYPE, AclEntryModified.class, @@ -310,7 +318,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.UPDATED, JsonPointer.empty(), e.getAclEntry().toJson(e.getImplementedSchemaVersion()), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AclEntryDeleted.TYPE, AclEntryDeleted.class, @@ -319,7 +328,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.DELETED, JsonPointer.empty(), null, - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); /* @@ -330,7 +340,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.CREATED, JsonPointer.empty(), e.getCreatedAttributes(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AttributesModified.TYPE, AttributesModified.class, @@ -338,7 +349,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.UPDATED, JsonPointer.empty(), e.getModifiedAttributes(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AttributesDeleted.TYPE, AttributesDeleted.class, @@ -346,7 +358,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.DELETED, JsonPointer.empty(), null, - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); /* @@ -358,7 +371,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.CREATED, e.getAttributePointer(), e.getAttributeValue(), - e.getRevision(), e.getTimestamp().orElse(null), extra)); + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal)); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AttributeModified.TYPE, AttributeModified.class, e -> MessageFormat.format(ATTRIBUTE_PATTERN, e.getThingEntityId(), @@ -366,7 +380,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.UPDATED, e.getAttributePointer(), e.getAttributeValue(), - e.getRevision(), e.getTimestamp().orElse(null), extra)); + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal)); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AttributeDeleted.TYPE, AttributeDeleted.class, e -> MessageFormat.format(ATTRIBUTE_PATTERN, e.getThingEntityId(), @@ -374,7 +389,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.DELETED, e.getAttributePointer(), null, - e.getRevision(), e.getTimestamp().orElse(null), extra)); + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal)); /* * Features @@ -384,7 +400,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableFeaturesChange(e.getThingEntityId(), ChangeAction.CREATED, e.getFeatures(), JsonPointer.empty(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturesModified.TYPE, FeaturesModified.class, @@ -392,7 +409,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableFeaturesChange(e.getThingEntityId(), ChangeAction.UPDATED, e.getFeatures(), JsonPointer.empty(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturesDeleted.TYPE, FeaturesDeleted.class, @@ -400,7 +418,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableFeaturesChange(e.getThingEntityId(), ChangeAction.DELETED, null, JsonPointer.empty(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); /* @@ -411,7 +430,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableFeatureChange(e.getThingEntityId(), ChangeAction.CREATED, e.getFeature(), JsonPointer.empty(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeatureModified.TYPE, FeatureModified.class, @@ -419,7 +439,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableFeatureChange(e.getThingEntityId(), ChangeAction.UPDATED, e.getFeature(), JsonPointer.empty(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeatureDeleted.TYPE, FeatureDeleted.class, @@ -427,7 +448,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableFeatureChange(e.getThingEntityId(), ChangeAction.DELETED, null, JsonPointer.empty(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); /* @@ -440,7 +462,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.CREATED, JsonPointer.empty(), e.getProperties().toJson(e.getImplementedSchemaVersion()), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturePropertiesModified.TYPE, @@ -450,7 +473,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.UPDATED, JsonPointer.empty(), e.getProperties().toJson(e.getImplementedSchemaVersion()), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturePropertiesDeleted.TYPE, @@ -460,7 +484,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.DELETED, JsonPointer.empty(), null, - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); /* @@ -473,7 +498,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.CREATED, e.getPropertyPointer(), e.getPropertyValue(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturePropertyModified.TYPE, @@ -483,7 +509,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.UPDATED, e.getPropertyPointer(), e.getPropertyValue(), - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturePropertyDeleted.TYPE, @@ -493,7 +520,8 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b (e, extra) -> new ImmutableChange(e.getThingEntityId(), ChangeAction.DELETED, e.getPropertyPointer(), null, - e.getRevision(), e.getTimestamp().orElse(null), extra) + e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), + messagingProvider::sendSignal) ); } diff --git a/java/src/main/java/org/eclipse/ditto/client/management/internal/FeatureHandleImpl.java b/java/src/main/java/org/eclipse/ditto/client/management/internal/FeatureHandleImpl.java index 96fb0b9d..03c78a75 100755 --- a/java/src/main/java/org/eclipse/ditto/client/management/internal/FeatureHandleImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/management/internal/FeatureHandleImpl.java @@ -19,7 +19,6 @@ import java.util.function.Consumer; import org.eclipse.ditto.client.changes.Change; -import org.eclipse.ditto.client.changes.internal.ImmutableChange; import org.eclipse.ditto.client.internal.HandlerRegistry; import org.eclipse.ditto.client.internal.OutgoingMessageFactory; import org.eclipse.ditto.client.internal.ResponseForwarder; @@ -251,9 +250,7 @@ public void registerForPropertyChanges(final String registrationId, final Consum argumentNotNull(handler); SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/{0}/features/{1}/properties", thingId, featureId), - Change.class, handler, (change, value, path, params) -> - new ImmutableChange(change.getEntityId(), change.getAction(), path, value, change.getRevision(), - change.getTimestamp().orElse(null), change.getExtra().orElse(null)) + Change.class, handler, (change, value, path, params) -> change.withPathAndValue(path, value) ); } @@ -264,9 +261,8 @@ public void registerForPropertyChanges(final String registrationId, final JsonPo argumentNotNull(handler); SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/{0}/features/{1}/properties{2}", thingId, featureId, - propertyPath), Change.class, handler, - (change, value, path, params) -> new ImmutableChange(change.getEntityId(), change.getAction(), path, - value, change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)) + propertyPath), Change.class, handler, (change, value, path, params) -> + change.withPathAndValue(path, value) ); } diff --git a/java/src/main/java/org/eclipse/ditto/client/management/internal/ThingHandleImpl.java b/java/src/main/java/org/eclipse/ditto/client/management/internal/ThingHandleImpl.java index 2f9d191d..6b9391f2 100755 --- a/java/src/main/java/org/eclipse/ditto/client/management/internal/ThingHandleImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/management/internal/ThingHandleImpl.java @@ -22,7 +22,6 @@ import org.eclipse.ditto.client.changes.FeatureChange; import org.eclipse.ditto.client.changes.FeaturesChange; import org.eclipse.ditto.client.changes.ThingChange; -import org.eclipse.ditto.client.changes.internal.ImmutableChange; import org.eclipse.ditto.client.changes.internal.ImmutableFeatureChange; import org.eclipse.ditto.client.changes.internal.ImmutableFeaturesChange; import org.eclipse.ditto.client.changes.internal.ImmutableThingChange; @@ -272,9 +271,7 @@ public void registerForAttributesChanges(final String registrationId, final Cons argumentNotNull(handler); SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/{0}/attributes", thingId), - Change.class, handler, (change, value, path, params) -> - new ImmutableChange(change.getEntityId(), change.getAction(), path, value, change.getRevision(), - change.getTimestamp().orElse(null), change.getExtra().orElse(null)) + Change.class, handler, (change, value, path, params) -> change.withPathAndValue(path, value) ); } @@ -285,9 +282,7 @@ public void registerForAttributeChanges(final String registrationId, final JsonP argumentNotNull(handler); SelectorUtil.registerForChanges(handlerRegistry, registrationId, SelectorUtil.formatJsonPointer(LOGGER, "/things/{0}/attributes{1}", thingId, attrPath), - Change.class, handler, (change, value, path, params) -> - new ImmutableChange(change.getEntityId(), change.getAction(), path, value, change.getRevision(), - change.getTimestamp().orElse(null), change.getExtra().orElse(null)) + Change.class, handler, (change, value, path, params) -> change.withPathAndValue(path, value) ); } @@ -301,8 +296,7 @@ public void registerForFeatureChanges(final String registrationId, final Consume ThingsModelFactory.newFeatureBuilder(value.asObject()) .useId(params.get("{featureId}")) .build() : null; - return new ImmutableFeatureChange(change.getEntityId(), change.getAction(), feature, path, - change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)); + return new ImmutableFeatureChange(change.withPathAndValue(path, value), feature); }); } @@ -316,8 +310,7 @@ public void registerForFeatureChanges(final String registrationId, final String FeatureChange.class, handler, (change, value, path, params) -> { final Feature feature = value != null ? ThingsModelFactory.newFeatureBuilder(value.asObject()).useId(featureId).build() : null; - return new ImmutableFeatureChange(change.getEntityId(), change.getAction(), feature, path, - change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)); + return new ImmutableFeatureChange(change.withPathAndValue(path, value), feature); }); } @@ -328,8 +321,7 @@ public void registerForFeaturesChanges(final String registrationId, final Consum SelectorUtil.formatJsonPointer(LOGGER, "/things/{0}/features", thingId), FeaturesChange.class, handler, (change, value, path, params) -> { final Features features = value != null ? ThingsModelFactory.newFeatures(value.asObject()) : null; - return new ImmutableFeaturesChange(change.getEntityId(), change.getAction(), features, path, - change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)); + return new ImmutableFeaturesChange(change.withPathAndValue(path, value), features); }); } @@ -341,8 +333,7 @@ public void registerForThingChanges(final String registrationId, final Consumer< (change, value, path, params) -> { final Thing thing = value != null ? ThingsModelFactory.newThingBuilder(value.asObject()).build() : null; - return new ImmutableThingChange(change.getEntityId(), change.getAction(), thing, path, - change.getRevision(), change.getTimestamp().orElse(null), change.getExtra().orElse(null)); + return new ImmutableThingChange(change.withPathAndValue(path, value), thing); }); } diff --git a/java/src/main/java/org/eclipse/ditto/client/messaging/MessagingProvider.java b/java/src/main/java/org/eclipse/ditto/client/messaging/MessagingProvider.java index 6b68e85c..3e9aa2a0 100644 --- a/java/src/main/java/org/eclipse/ditto/client/messaging/MessagingProvider.java +++ b/java/src/main/java/org/eclipse/ditto/client/messaging/MessagingProvider.java @@ -22,6 +22,7 @@ import org.eclipse.ditto.model.messages.Message; import org.eclipse.ditto.protocoladapter.Adaptable; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.commands.base.Command; import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.events.base.Event; @@ -68,6 +69,12 @@ public interface MessagingProvider { */ CompletableFuture sendAdaptable(Adaptable adaptable); + /** + * TODO TJ remove again after search branch was merged - this should be easier then! + * @param signal + */ + void sendSignal(Signal signal); + /** * Send message using the underlying connection. * diff --git a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java index 9d44ec95..b84bc7ab 100644 --- a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java +++ b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java @@ -499,6 +499,17 @@ public CompletableFuture sendAdaptable(final Adaptable adaptable) { return responseFuture; } + @Override + public void sendSignal(final Signal signal) { + try { + final Signal adjustedSignal = signal.setDittoHeaders(adjustHeadersForLive(signal)); + final Adaptable adaptable = protocolAdapter.toAdaptable(adjustedSignal); + doSendAdaptable(adaptable); + } catch (final UnknownCommandException e) { + logUnknownType(signal, e); + } + } + private void doSendAdaptable(@Nullable final Adaptable adaptable) { if (null == adaptable) { return; diff --git a/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableAcknowledgementRequestHandleTest.java b/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableAcknowledgementRequestHandleTest.java new file mode 100644 index 00000000..172f978f --- /dev/null +++ b/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableAcknowledgementRequestHandleTest.java @@ -0,0 +1,46 @@ +/* + * 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 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.client.changes.internal; + +import static org.mutabilitydetector.unittesting.AllowedReason.provided; +import static org.mutabilitydetector.unittesting.MutabilityAssert.assertInstancesOf; +import static org.mutabilitydetector.unittesting.MutabilityMatchers.areImmutable; + +import java.util.function.Consumer; + +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; +import org.eclipse.ditto.model.base.entity.id.EntityIdWithType; +import org.eclipse.ditto.model.base.headers.DittoHeaders; +import org.junit.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +/** + * Unit tests for {@link ImmutableAcknowledgementRequestHandle}. + */ +public class ImmutableAcknowledgementRequestHandleTest { + + @Test + public void assertImmutability() { + assertInstancesOf(ImmutableAcknowledgementRequestHandle.class, areImmutable(), + provided(AcknowledgementLabel.class, EntityIdWithType.class, DittoHeaders.class, Consumer.class) + .isAlsoImmutable()); + } + + @Test + public void testHashCodeAndEquals() { + EqualsVerifier.forClass(ImmutableAcknowledgementRequestHandle.class) + .withIgnoredFields("acknowledgementPublisher") + .verify(); + } +} \ No newline at end of file diff --git a/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableChangeTest.java b/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableChangeTest.java index 919f962b..ca61020e 100644 --- a/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableChangeTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableChangeTest.java @@ -16,10 +16,13 @@ import static org.mutabilitydetector.unittesting.MutabilityAssert.assertInstancesOf; import static org.mutabilitydetector.unittesting.MutabilityMatchers.areImmutable; +import java.util.function.Consumer; + import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; -import org.eclipse.ditto.model.base.entity.id.EntityId; +import org.eclipse.ditto.model.base.entity.id.EntityIdWithType; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.junit.Test; import nl.jqno.equalsverifier.EqualsVerifier; @@ -29,21 +32,18 @@ */ public final class ImmutableChangeTest { - /** - * - */ @Test public void assertImmutability() { assertInstancesOf(ImmutableChange.class, areImmutable(), - provided(JsonValue.class, JsonPointer.class, EntityId.class, JsonObject.class).isAlsoImmutable()); + provided(JsonValue.class, JsonPointer.class, EntityIdWithType.class, JsonObject.class, + DittoHeaders.class, Consumer.class).isAlsoImmutable()); } - /** - * - */ @Test public void testHashCodeAndEquals() { - EqualsVerifier.forClass(ImmutableChange.class).verify(); + EqualsVerifier.forClass(ImmutableChange.class) + .withIgnoredFields("acknowledgementPublisher") + .verify(); } } diff --git a/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableThingChangeTest.java b/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableThingChangeTest.java index 89f435a0..00402549 100644 --- a/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableThingChangeTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/changes/internal/ImmutableThingChangeTest.java @@ -21,12 +21,15 @@ import java.time.Instant; import java.util.Optional; +import java.util.function.Consumer; import org.eclipse.ditto.client.changes.Change; import org.eclipse.ditto.client.changes.ChangeAction; import org.eclipse.ditto.client.changes.ThingChange; import org.eclipse.ditto.json.JsonPointer; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.things.Thing; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; import org.junit.Test; import org.mockito.Mockito; @@ -42,12 +45,14 @@ public final class ImmutableThingChangeTest { private static final JsonPointer POINTER_MOCK = Mockito.mock(JsonPointer.class); private static final long KNOWN_REVISION = 34L; private static final Instant KNOWN_TIMESTAMP = Instant.now(); + private static final DittoHeaders KNOWN_DITTO_HEADERS = DittoHeaders.newBuilder().correlationId("cor-id").build(); + private static final Consumer ACK_CONSUMER = acknowledgement -> {}; @Test public void constructWithValidThingIdAndType() { final ThingChange thingChange = new ImmutableThingChange(THING_ID, KNOWN_ACTION, THING_MOCK, POINTER_MOCK, KNOWN_REVISION, - KNOWN_TIMESTAMP, null); + KNOWN_TIMESTAMP, null, KNOWN_DITTO_HEADERS, ACK_CONSUMER); assertThat(thingChange).isNotNull(); } @@ -56,7 +61,7 @@ public void constructWithValidThingIdAndType() { public void constructWithNullThingId() { assertThatNullPointerException() .isThrownBy(() -> new ImmutableThingChange(null, KNOWN_ACTION, THING_MOCK, POINTER_MOCK, KNOWN_REVISION, - KNOWN_TIMESTAMP, null)) + KNOWN_TIMESTAMP, null, KNOWN_DITTO_HEADERS, ACK_CONSUMER)) .withMessage("The %s must not be null!", "Thing ID") .withNoCause(); } @@ -66,7 +71,7 @@ public void constructWithChangeAction() { assertThatNullPointerException() .isThrownBy( () -> new ImmutableThingChange(THING_ID, null, THING_MOCK, POINTER_MOCK, KNOWN_REVISION, - KNOWN_TIMESTAMP, null)) + KNOWN_TIMESTAMP, null, KNOWN_DITTO_HEADERS, ACK_CONSUMER)) .withMessage("The %s must not be null!", "change action") .withNoCause(); } @@ -89,7 +94,7 @@ public void testHashCodeAndEquals() { public void getHashCodeForChangeWithNullThing() { final ImmutableThingChange underTest = new ImmutableThingChange(THING_ID, KNOWN_ACTION, null, POINTER_MOCK, KNOWN_REVISION, - KNOWN_TIMESTAMP, null); + KNOWN_TIMESTAMP, null, KNOWN_DITTO_HEADERS, ACK_CONSUMER); final int hashCode = underTest.hashCode(); @@ -100,7 +105,7 @@ public void getHashCodeForChangeWithNullThing() { public void gettersReturnExpected() { final ThingChange underTest = new ImmutableThingChange(THING_ID, KNOWN_ACTION, THING_MOCK, POINTER_MOCK, KNOWN_REVISION, - KNOWN_TIMESTAMP, null); + KNOWN_TIMESTAMP, null, KNOWN_DITTO_HEADERS, ACK_CONSUMER); assertThat((CharSequence) underTest.getEntityId()).isEqualTo(THING_ID); assertThat(underTest.getAction()).isSameAs(KNOWN_ACTION); @@ -111,7 +116,7 @@ public void gettersReturnExpected() { public void createEventWithThing() { final ThingChange underTest = new ImmutableThingChange(THING_ID, KNOWN_ACTION, THING_MOCK, POINTER_MOCK, KNOWN_REVISION, - KNOWN_TIMESTAMP, null); + KNOWN_TIMESTAMP, null, KNOWN_DITTO_HEADERS, ACK_CONSUMER); final Optional thing = underTest.getThing(); diff --git a/java/src/test/java/org/eclipse/ditto/client/messaging/mock/MockMessagingProvider.java b/java/src/test/java/org/eclipse/ditto/client/messaging/mock/MockMessagingProvider.java index 21e0e457..3183aab0 100644 --- a/java/src/test/java/org/eclipse/ditto/client/messaging/mock/MockMessagingProvider.java +++ b/java/src/test/java/org/eclipse/ditto/client/messaging/mock/MockMessagingProvider.java @@ -38,12 +38,9 @@ import org.eclipse.ditto.model.messages.MessageDirection; import org.eclipse.ditto.model.messages.MessageHeaders; import org.eclipse.ditto.model.messages.MessageHeadersBuilder; -import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.protocoladapter.Adaptable; -import org.eclipse.ditto.protocoladapter.JsonifiableAdaptable; -import org.eclipse.ditto.protocoladapter.Payload; -import org.eclipse.ditto.protocoladapter.ProtocolFactory; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.base.WithFeatureId; import org.eclipse.ditto.signals.commands.base.Command; import org.eclipse.ditto.signals.commands.base.CommandResponse; @@ -117,6 +114,11 @@ public CompletableFuture sendAdaptable(final Adaptable adaptable) { return CompletableFuture.completedFuture(null); } + @Override + public void sendSignal(final Signal signal) { + // ignore + } + @Override public void send(final Message message, final TopicPath.Channel channel) { Objects.requireNonNull(out); From 38c4d1cba9879626c7b256c61a415728f878cf4b Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Fri, 3 Apr 2020 13:46:06 +0200 Subject: [PATCH 08/23] removed empty test comments Signed-off-by: Thomas Jaeckle --- .../ditto/client/options/OptionName.java | 6 ++- ...ChangeUpwardsDownwardsPropagationTest.java | 1 - .../assertions/AbstractThingChangeAssert.java | 4 +- .../client/internal/HandlerRegistryTest.java | 26 +--------- .../ImmutableFeatureEventFactoryTest.java | 13 +---- .../ImmutableGlobalEventFactoryTest.java | 51 ------------------- .../ImmutableThingEventFactoryTest.java | 13 +---- .../DefaultMessageSerializerRegistryTest.java | 27 ---------- .../DefaultMessageSerializerTest.java | 4 +- .../ImmutableDeserializingMessageTest.java | 7 +-- .../ImmutableMessageSerializerKeyTest.java | 7 +-- .../ImmutableRepliableMessageTest.java | 7 +-- .../client/options/ConsumeOptionNameTest.java | 9 ---- .../client/options/ConsumeOptionsTest.java | 6 --- .../client/options/DefaultOptionTest.java | 24 --------- .../ditto/client/options/OptionsTest.java | 3 -- .../internal/ConsumeOptionsEvaluatorTest.java | 28 +++------- .../CopyPolicyFromThingOptionVisitorTest.java | 16 +----- .../internal/CopyPolicyOptionVisitorTest.java | 16 +----- .../internal/ExistsOptionVisitorTest.java | 16 +----- .../ExtraFieldsOptionVisitorTest.java | 16 +----- .../internal/FilterOptionVisitorTest.java | 16 +----- .../internal/NamespacesOptionVisitorTest.java | 16 +----- .../internal/OptionsValidatorTest.java | 13 +---- .../ResponseRequiredOptionVisitorTest.java | 16 +----- .../internal/UserProvidedOptionsTest.java | 19 +------ 26 files changed, 29 insertions(+), 351 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/options/OptionName.java b/java/src/main/java/org/eclipse/ditto/client/options/OptionName.java index bb61ff97..d88c105a 100755 --- a/java/src/main/java/org/eclipse/ditto/client/options/OptionName.java +++ b/java/src/main/java/org/eclipse/ditto/client/options/OptionName.java @@ -35,7 +35,11 @@ default boolean test(final Object o) { * @since 1.0.0 */ enum Global implements OptionName { - // currently empty + /** + * Name of the option for defining the DittoHeaders to send along with a command/message to the Ditto backend. + * @since 1.1.0 + */ + DITTO_HEADERS } /** diff --git a/java/src/test/java/org/eclipse/ditto/client/ChangeUpwardsDownwardsPropagationTest.java b/java/src/test/java/org/eclipse/ditto/client/ChangeUpwardsDownwardsPropagationTest.java index eae763a2..51e39df2 100755 --- a/java/src/test/java/org/eclipse/ditto/client/ChangeUpwardsDownwardsPropagationTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/ChangeUpwardsDownwardsPropagationTest.java @@ -227,7 +227,6 @@ public void testMultipleChangeHandlersAreInvokedOnSingleChange() throws Exceptio assertEquals(0, latch.getCount()); } - @Test public void testUpwardsRegisterForThingChangeWhenThingIsDeleted() throws Exception { // start consuming changes: diff --git a/java/src/test/java/org/eclipse/ditto/client/assertions/AbstractThingChangeAssert.java b/java/src/test/java/org/eclipse/ditto/client/assertions/AbstractThingChangeAssert.java index 1ec266ab..51315f2f 100644 --- a/java/src/test/java/org/eclipse/ditto/client/assertions/AbstractThingChangeAssert.java +++ b/java/src/test/java/org/eclipse/ditto/client/assertions/AbstractThingChangeAssert.java @@ -20,9 +20,7 @@ import org.eclipse.ditto.client.changes.ChangeAction; import org.eclipse.ditto.model.things.ThingId; -/** - * - */ + public abstract class AbstractThingChangeAssert, T extends Change> extends AbstractAssert { diff --git a/java/src/test/java/org/eclipse/ditto/client/internal/HandlerRegistryTest.java b/java/src/test/java/org/eclipse/ditto/client/internal/HandlerRegistryTest.java index 52bca3df..720f5b33 100755 --- a/java/src/test/java/org/eclipse/ditto/client/internal/HandlerRegistryTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/internal/HandlerRegistryTest.java @@ -52,9 +52,7 @@ public class HandlerRegistryTest { private Registration> registrationMock; private HandlerRegistry registry; - /** - * - */ + @Before public void before() { registry = new HandlerRegistry(busMock); @@ -62,17 +60,11 @@ public void before() { when(busMock.on(any(JsonPointerSelector.class), any(Consumer.class))).thenReturn(registrationMock); } - /** - * - */ @Test(expected = NullPointerException.class) public void constructorWithNullBus() { new HandlerRegistry(null); } - /** - * - */ @Test public void registerWithNewRegistrationId() { // test @@ -82,9 +74,6 @@ public void registerWithNewRegistrationId() { verify(busMock).on(selectorMock, consumerMock); } - /** - * - */ @Test public void registerWithAlreadyExistingRegistrationId() { // prepare @@ -103,10 +92,6 @@ public void registerWithAlreadyExistingRegistrationId() { verify(busMock, never()).on(selectorMock, consumerMock); } - - /** - * - */ @Test public void registerTwoConsumersWithDifferentRegistrationId() { // test @@ -117,9 +102,6 @@ public void registerTwoConsumersWithDifferentRegistrationId() { verify(busMock, times(2)).on(selectorMock, consumerMock); } - /** - * - */ @Test public void deregisterWithKnownRegistrationId() { // prepare @@ -133,9 +115,6 @@ public void deregisterWithKnownRegistrationId() { verify(registrationMock).cancel(); } - /** - * - */ @Test public void deregisterWithUnknownRegistrationId() { // test @@ -145,9 +124,6 @@ public void deregisterWithUnknownRegistrationId() { assertFalse(deregistered); } - /** - * - */ @Test public void deregisterAndRegisterAgain() { // prepare diff --git a/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableFeatureEventFactoryTest.java b/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableFeatureEventFactoryTest.java index 52638303..f7c142f6 100755 --- a/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableFeatureEventFactoryTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableFeatureEventFactoryTest.java @@ -35,17 +35,12 @@ public final class ImmutableFeatureEventFactoryTest { private ImmutableFeatureEventFactory underTest = null; - /** - * - */ + @Before public void setUp() { underTest = ImmutableFeatureEventFactory.getInstance(SCHEMA_VERSION, THING_ID, FLUX_CAPACITOR_ID); } - /** - * - */ @Test public void assertImmutability() { assertInstancesOf(ImmutableFeatureEventFactory.class, @@ -53,17 +48,11 @@ public void assertImmutability() { provided(ThingEventFactory.class).isAlsoImmutable()); } - /** - * - */ @Test public void testHashCodeAndEquals() { EqualsVerifier.forClass(ImmutableFeatureEventFactory.class).usingGetClass().verify(); } - /** - * - */ @Test public void toStringReturnsExpected() { assertThat(underTest.toString()) diff --git a/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableGlobalEventFactoryTest.java b/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableGlobalEventFactoryTest.java index cdfe0cf3..93cb493e 100755 --- a/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableGlobalEventFactoryTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableGlobalEventFactoryTest.java @@ -169,9 +169,6 @@ public void attributeCreatedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void attributeDeletedReturnsExpected() { final AttributeDeleted attributeDeleted = underTest.attributeDeleted(THING_ID, ATTRIBUTE_JSON_POINTER); @@ -188,9 +185,6 @@ public void attributeDeletedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void attributeModifiedReturnsExpected() { final AttributeModified attributeModified = underTest.attributeModified(THING_ID, ATTRIBUTE_JSON_POINTER, @@ -208,9 +202,6 @@ public void attributeModifiedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void attributesCreatedReturnsExpected() { final AttributesCreated attributesCreated = underTest.attributesCreated(THING_ID, ATTRIBUTES); @@ -227,9 +218,6 @@ public void attributesCreatedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void attributesDeletedReturnsExpected() { final AttributesDeleted attributesDeleted = underTest.attributesDeleted(THING_ID); @@ -246,9 +234,6 @@ public void attributesDeletedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void attributesModifiedReturnsExpected() { final AttributesModified attributesModified = underTest.attributesModified(THING_ID, ATTRIBUTES); @@ -265,9 +250,6 @@ public void attributesModifiedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featureCreatedReturnsExpected() { final FeatureCreated featureCreated = underTest.featureCreated(THING_ID, FLUX_CAPACITOR); @@ -284,9 +266,6 @@ public void featureCreatedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featureDeletedReturnsExpected() { final FeatureDeleted featureDeleted = underTest.featureDeleted(THING_ID, FLUX_CAPACITOR_ID); @@ -303,9 +282,6 @@ public void featureDeletedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featureModifiedReturnsExpected() { final FeatureModified featureModified = underTest.featureModified(THING_ID, FLUX_CAPACITOR); @@ -322,9 +298,6 @@ public void featureModifiedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featuresCreatedReturnsExpected() { final FeaturesCreated featuresCreated = underTest.featuresCreated(THING_ID, FEATURES); @@ -341,9 +314,6 @@ public void featuresCreatedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featuresDeletedReturnsExpected() { final FeaturesDeleted featuresDeleted = underTest.featuresDeleted(THING_ID); @@ -360,9 +330,6 @@ public void featuresDeletedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featuresModifiedReturnsExpected() { final FeaturesModified featuresModified = underTest.featuresModified(THING_ID, FEATURES); @@ -379,9 +346,6 @@ public void featuresModifiedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featurePropertiesCreatedReturnsExpected() { final FeaturePropertiesCreated featurePropertiesCreated = @@ -399,9 +363,6 @@ public void featurePropertiesCreatedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featurePropertiesDeletedReturnsExpected() { final FeaturePropertiesDeleted featurePropertiesDeleted = @@ -419,9 +380,6 @@ public void featurePropertiesDeletedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featurePropertiesModifiedReturnsExpected() { final FeaturePropertiesModified featurePropertiesModified = @@ -439,9 +397,6 @@ public void featurePropertiesModifiedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featurePropertyCreatedReturnsExpected() { final FeaturePropertyCreated featurePropertyCreated = @@ -460,9 +415,6 @@ public void featurePropertyCreatedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featurePropertyDeletedReturnsExpected() { final FeaturePropertyDeleted featurePropertyDeleted = @@ -481,9 +433,6 @@ public void featurePropertyDeletedReturnsExpected() { .hasSchemaVersion(underTest.getSchemaVersion()); } - /** - * - */ @Test public void featurePropertyModifiedReturnsExpected() { final FeaturePropertyModified featurePropertyModified = diff --git a/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableThingEventFactoryTest.java b/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableThingEventFactoryTest.java index 1a7596cf..c569a02b 100755 --- a/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableThingEventFactoryTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/live/events/internal/ImmutableThingEventFactoryTest.java @@ -35,17 +35,12 @@ public final class ImmutableThingEventFactoryTest { private ImmutableThingEventFactory underTest = null; - /** - * - */ + @Before public void setUp() { underTest = ImmutableThingEventFactory.getInstance(SCHEMA_VERSION, TestConstants.Thing.THING_ID); } - /** - * - */ @Test public void assertImmutability() { assertInstancesOf(ImmutableThingEventFactory.class, @@ -53,17 +48,11 @@ public void assertImmutability() { provided(GlobalEventFactory.class, ThingId.class).areAlsoImmutable()); } - /** - * - */ @Test public void testHashCodeAndEquals() { EqualsVerifier.forClass(ImmutableThingEventFactory.class).usingGetClass().verify(); } - /** - * - */ @Test public void toStringReturnsExpected() { assertThat(underTest.toString()) diff --git a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/DefaultMessageSerializerRegistryTest.java b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/DefaultMessageSerializerRegistryTest.java index 0767f68d..6a05c5c0 100755 --- a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/DefaultMessageSerializerRegistryTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/DefaultMessageSerializerRegistryTest.java @@ -46,9 +46,6 @@ public void setupBefore() { sut = new DefaultMessageSerializerRegistry(); } - /** - * - */ @Test(expected = MessageSerializationException.class) public void registerMessageSerializerTwiceResultsInException() { final MessageSerializerKey key = ImmutableMessageSerializerKey.of(TEXT_PLAIN, String.class); @@ -63,9 +60,6 @@ public void registerMessageSerializerTwiceResultsInException() { Assert.fail("Registering a messageSerializer for the twice should have failed!"); } - /** - * - */ @Test public void registerMessageSerializerAndUnregisterToNewRegister() { final MessageSerializerKey key = ImmutableMessageSerializerKey.of(TEXT_PLAIN, String.class); @@ -81,9 +75,6 @@ public void registerMessageSerializerAndUnregisterToNewRegister() { sut.registerMessageSerializer(messageSerializer); } - /** - * - */ @Test public void registerMessageSerializerAndCheckForExistance() { final MessageSerializerKey key = ImmutableMessageSerializerKey.of(TEXT_PLAIN, String.class); @@ -104,9 +95,6 @@ public void registerMessageSerializerAndCheckForExistance() { sut.containsMessageSerializerFor(key.getJavaType(), key.getSubject())); } - /** - * - */ @Test public void findMessageSerializerWithDifferentSubjects() { final MessageSerializerKey @@ -132,9 +120,6 @@ public void findMessageSerializerWithDifferentSubjects() { sut.findSerializerFor(key2).get().getDeserializer()); } - /** - * - */ @Test public void findMessageSerializerWithDifferentSubjectsAndFallback() { final MessageSerializerKey key0 = ImmutableMessageSerializerKey.of(TEXT_PLAIN, String.class); @@ -180,9 +165,6 @@ public void findMessageSerializerWithDifferentSubjectsAndFallback() { sut.findSerializerFor("foo/bar", String.class).get().getSerializer()); } - /** - * - */ @Test public void findMessageSerializerWithTypeInheritance() { final MessageSerializerKey key0 = @@ -211,9 +193,6 @@ public void findMessageSerializerWithTypeInheritance() { sut.findSerializerFor(JsonArray.class).get().getSerializer()); } - /** - * - */ @Test public void findMessageSerializerKey() { sut.registerMessageSerializer(MessageSerializers.textPlainAsString()); @@ -234,9 +213,6 @@ public void findMessageSerializerKey() { sut.findKeyFor(ByteBuffer.class).get().getContentType()); } - /** - * - */ @Test public void findUnkownMessageSerializerKey() { sut.registerMessageSerializer(MessageSerializers.textPlainAsString()); @@ -247,9 +223,6 @@ public void findUnkownMessageSerializerKey() { sut.findKeyFor(JsonValue.class).isPresent()); } - /** - * - */ @Test public void registerMultipleSerialzersForSameContentType() { final MessageSerializerKey key0 = diff --git a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/DefaultMessageSerializerTest.java b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/DefaultMessageSerializerTest.java index 1c66545c..a4654c61 100755 --- a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/DefaultMessageSerializerTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/DefaultMessageSerializerTest.java @@ -21,9 +21,7 @@ */ public class DefaultMessageSerializerTest { - /** - * - */ + @Test public void testHashCodeAndEquals() { EqualsVerifier.forClass(DefaultMessageSerializer.class).verify(); diff --git a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableDeserializingMessageTest.java b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableDeserializingMessageTest.java index 62a54801..eac3db85 100755 --- a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableDeserializingMessageTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableDeserializingMessageTest.java @@ -27,18 +27,13 @@ */ public class ImmutableDeserializingMessageTest { - /** - * - */ + @Test public void assertImmutability() { MutabilityAssert.assertInstancesOf(ImmutableDeserializingMessage.class, areImmutable(), provided( Message.class, MessageSerializerRegistry.class).areAlsoImmutable()); } - /** - * - */ @Test public void testHashCodeAndEquals() { EqualsVerifier.forClass(ImmutableDeserializingMessage.class).verify(); diff --git a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableMessageSerializerKeyTest.java b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableMessageSerializerKeyTest.java index 88349645..af15e884 100755 --- a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableMessageSerializerKeyTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableMessageSerializerKeyTest.java @@ -24,17 +24,12 @@ */ public class ImmutableMessageSerializerKeyTest { - /** - * - */ + @Test public void assertImmutability() { MutabilityAssert.assertInstancesOf(ImmutableMessageSerializerKey.class, areImmutable()); } - /** - * - */ @Test public void testHashCodeAndEquals() { EqualsVerifier.forClass(ImmutableMessageSerializerKey.class).verify(); diff --git a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableRepliableMessageTest.java b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableRepliableMessageTest.java index b3bc80f2..b3b98302 100755 --- a/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableRepliableMessageTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/live/messages/internal/ImmutableRepliableMessageTest.java @@ -28,18 +28,13 @@ */ public class ImmutableRepliableMessageTest { - /** - * - */ + @Test public void assertImmutability() { MutabilityAssert.assertInstancesOf(ImmutableRepliableMessage.class, areImmutable(), provided( Message.class, Consumer.class).areAlsoImmutable()); } - /** - * - */ @Test public void testHashCodeAndEquals() { EqualsVerifier.forClass(ImmutableRepliableMessage.class).verify(); diff --git a/java/src/test/java/org/eclipse/ditto/client/options/ConsumeOptionNameTest.java b/java/src/test/java/org/eclipse/ditto/client/options/ConsumeOptionNameTest.java index 3fcaa4f4..7bccfdbf 100755 --- a/java/src/test/java/org/eclipse/ditto/client/options/ConsumeOptionNameTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/ConsumeOptionNameTest.java @@ -21,9 +21,6 @@ */ public final class ConsumeOptionNameTest { - /** - * - */ @Test public void testAgainstValidStringValueReturnsTrue() { final String optionNameValue = OptionName.Modify.RESPONSE_REQUIRED.toString(); @@ -31,17 +28,11 @@ public void testAgainstValidStringValueReturnsTrue() { assertThat(OptionName.Modify.RESPONSE_REQUIRED.test(optionNameValue)).isTrue(); } - /** - * - */ @Test public void testAgainstInvalidStringValueReturnsFalse() { assertThat(OptionName.Modify.RESPONSE_REQUIRED.test("Fnord")).isFalse(); } - /** - * - */ @Test public void testAgainstSameOptionNameReturnsTrue() { final OptionName optionName = OptionName.Modify.RESPONSE_REQUIRED; diff --git a/java/src/test/java/org/eclipse/ditto/client/options/ConsumeOptionsTest.java b/java/src/test/java/org/eclipse/ditto/client/options/ConsumeOptionsTest.java index c4faf18e..007a9b2b 100755 --- a/java/src/test/java/org/eclipse/ditto/client/options/ConsumeOptionsTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/ConsumeOptionsTest.java @@ -23,17 +23,11 @@ */ public final class ConsumeOptionsTest { - /** - * - */ @Test public void assertImmutability() { assertInstancesOf(Options.Modify.class, areImmutable()); } - /** - * - */ @Test public void responseTimeoutWithDurationReturnsExpectedOption() { final boolean responseRequired = false; diff --git a/java/src/test/java/org/eclipse/ditto/client/options/DefaultOptionTest.java b/java/src/test/java/org/eclipse/ditto/client/options/DefaultOptionTest.java index 832b18b8..6554b447 100755 --- a/java/src/test/java/org/eclipse/ditto/client/options/DefaultOptionTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/DefaultOptionTest.java @@ -27,26 +27,17 @@ public final class DefaultOptionTest { private static final OptionName DEFAULT_OPTION_NAME = OptionName.Modify.RESPONSE_REQUIRED; - /** - * - */ @Test public void testHashCodeAndEquals() { EqualsVerifier.forClass(DefaultOption.class).verify(); } - /** - * - */ @Test public void tryToCreateNewInstanceWithNullName() { assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> DefaultOption.newInstance(null, 0)) .withMessage("The option name must not be null!"); } - /** - * - */ @Test public void tryToCreateNewInstanceWithNullValue() { assertThatExceptionOfType(NullPointerException.class).isThrownBy( @@ -54,9 +45,6 @@ public void tryToCreateNewInstanceWithNullValue() { .withMessage("The option value must not be null!"); } - /** - * - */ @Test public void getNameReturnsExpected() { final DefaultOption underTest = DefaultOption.newInstance(DEFAULT_OPTION_NAME, 0); @@ -64,9 +52,6 @@ public void getNameReturnsExpected() { assertThat(underTest).hasName(DEFAULT_OPTION_NAME); } - /** - * - */ @Test public void getValueReturnsExpected() { final int value = 1337; @@ -75,9 +60,6 @@ public void getValueReturnsExpected() { Assertions.assertThat(underTest.getValue()).isEqualTo(value); } - /** - * - */ @Test public void tryToGetValueAsNullType() { final int value = 1337; @@ -87,9 +69,6 @@ public void tryToGetValueAsNullType() { .withMessage("The target type to cast the value of this option to must not be null!"); } - /** - * - */ @Test public void tryToGetIntValueAsString() { final int value = 1337; @@ -99,9 +78,6 @@ public void tryToGetIntValueAsString() { assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> underTest.getValueAs(stringClass)); } - /** - * - */ @Test public void getHiddenIntegerValueAsInteger() { final Integer value = 1337; diff --git a/java/src/test/java/org/eclipse/ditto/client/options/OptionsTest.java b/java/src/test/java/org/eclipse/ditto/client/options/OptionsTest.java index ea59a056..0884984a 100755 --- a/java/src/test/java/org/eclipse/ditto/client/options/OptionsTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/OptionsTest.java @@ -22,9 +22,6 @@ */ public final class OptionsTest { - /** - * - */ @Test public void assertImmutability() { assertInstancesOf(Options.class, areImmutable()); diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumeOptionsEvaluatorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumeOptionsEvaluatorTest.java index 1138ea0b..ca4c174d 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumeOptionsEvaluatorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumeOptionsEvaluatorTest.java @@ -35,45 +35,35 @@ public final class ConsumeOptionsEvaluatorTest { private OptionsEvaluator.Modify underTest = null; - /** - * - */ + @Before public void setUp() { final Option[] options = new Option[]{RESPONSE_REQUIRED_OPTION}; underTest = OptionsEvaluator.forModifyOptions(options); } - /** - * - */ + @Test public void assertThatOptionsEvaluatorIsImmutable() { assertInstancesOf(OptionsEvaluator.class, areImmutable(), provided(UserProvidedOptions.class).isAlsoImmutable()); } - /** - * - */ + @Test public void assertImmutability() { assertInstancesOf(OptionsEvaluator.Modify.class, areImmutable(), provided(OptionsEvaluator.class).isAlsoImmutable()); } - /** - * - */ + @Test public void tryToCreateInstanceWithNullOptions() { assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> OptionsEvaluator.forModifyOptions(null)) .withMessage("The options must not be null!"); } - /** - * - */ + @Test public void createInstanceWithEmptyOptions() { final OptionsEvaluator.Modify underTest = OptionsEvaluator.forModifyOptions(new Option[0]); @@ -81,17 +71,13 @@ public void createInstanceWithEmptyOptions() { assertThat(underTest).isNotNull(); } - /** - * - */ + @Test public void getResponseTimeoutReturnsExpectedIfProvided() { assertThat(underTest.isResponseRequired()).contains(RESPONSE_REQUIRED_OPTION.getValue()); } - /** - * - */ + @Test public void getResponseTimeoutReturnsEmptyOptionalIfNotProvided() { final Option[] options = new Option[]{}; diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/CopyPolicyFromThingOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/CopyPolicyFromThingOptionVisitorTest.java index 64a79ee1..61f7f860 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/CopyPolicyFromThingOptionVisitorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/CopyPolicyFromThingOptionVisitorTest.java @@ -28,17 +28,12 @@ public final class CopyPolicyFromThingOptionVisitorTest { private CopyPolicyFromThingOptionVisitor underTest = null; - /** - * - */ + @Before public void setUp() { underTest = new CopyPolicyFromThingOptionVisitor(); } - /** - * - */ @Test public void tryToVisitNullOption() { assertThatExceptionOfType(NullPointerException.class) @@ -47,9 +42,6 @@ public void tryToVisitNullOption() { .withMessageContaining("null"); } - /** - * - */ @Test public void getNoValueIfOptionNameIsUnexpected() { final String value = "Booh!"; @@ -65,9 +57,6 @@ public boolean test(final Object o) { assertThat(underTest.getValue()).isEmpty(); } - /** - * - */ @Test public void optionValueTypeDiffersFromExpectedType() { final String value = "Booh!"; @@ -78,9 +67,6 @@ public void optionValueTypeDiffersFromExpectedType() { .withCauseInstanceOf(ClassCastException.class); } - /** - * - */ @Test public void optionValueIsExpected() { final ThingId thingId = ThingId.inDefaultNamespace("thing"); diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/CopyPolicyOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/CopyPolicyOptionVisitorTest.java index 354aa98d..99f6a252 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/CopyPolicyOptionVisitorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/CopyPolicyOptionVisitorTest.java @@ -28,17 +28,12 @@ public final class CopyPolicyOptionVisitorTest { private CopyPolicyOptionVisitor underTest = null; - /** - * - */ + @Before public void setUp() { underTest = new CopyPolicyOptionVisitor(); } - /** - * - */ @Test public void tryToVisitNullOption() { assertThatExceptionOfType(NullPointerException.class) @@ -47,9 +42,6 @@ public void tryToVisitNullOption() { .withMessageContaining("null"); } - /** - * - */ @Test public void getNoValueIfOptionNameIsUnexpected() { final String value = "Booh!"; @@ -65,9 +57,6 @@ public boolean test(final Object o) { assertThat(underTest.getValue()).isEmpty(); } - /** - * - */ @Test public void optionValueTypeDiffersFromExpectedType() { final String value = "Booh!"; @@ -78,9 +67,6 @@ public void optionValueTypeDiffersFromExpectedType() { .withCauseInstanceOf(ClassCastException.class); } - /** - * - */ @Test public void optionValueIsExpected() { final PolicyId policyId = PolicyId.inNamespaceWithRandomName("org.eclipse.ditto"); diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/ExistsOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/ExistsOptionVisitorTest.java index 571f0e99..6123831e 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/ExistsOptionVisitorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/ExistsOptionVisitorTest.java @@ -27,17 +27,12 @@ public final class ExistsOptionVisitorTest { private ExistsOptionVisitor underTest = null; - /** - * - */ + @Before public void setUp() { underTest = new ExistsOptionVisitor(); } - /** - * - */ @Test public void tryToVisitNullOption() { assertThatExceptionOfType(NullPointerException.class) @@ -46,9 +41,6 @@ public void tryToVisitNullOption() { .withMessageContaining("null"); } - /** - * - */ @Test public void getNoValueIfOptionNameIsUnexpected() { final String value = "Booh!"; @@ -64,9 +56,6 @@ public boolean test(final Object o) { assertThat(underTest.getValue()).isEmpty(); } - /** - * - */ @Test public void optionValueTypeDiffersFromExpectedType() { final String value = "Booh!"; @@ -77,9 +66,6 @@ public void optionValueTypeDiffersFromExpectedType() { .withCauseInstanceOf(ClassCastException.class); } - /** - * - */ @Test public void optionValueIsExpected() { final boolean responseRequired = false; diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/ExtraFieldsOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/ExtraFieldsOptionVisitorTest.java index 4cf31028..51bf8678 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/ExtraFieldsOptionVisitorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/ExtraFieldsOptionVisitorTest.java @@ -29,17 +29,12 @@ public final class ExtraFieldsOptionVisitorTest { private ExtraFieldsOptionVisitor underTest = null; - /** - * - */ + @Before public void setUp() { underTest = new ExtraFieldsOptionVisitor(); } - /** - * - */ @Test public void tryToVisitNullOption() { assertThatExceptionOfType(NullPointerException.class) @@ -48,9 +43,6 @@ public void tryToVisitNullOption() { .withMessageContaining("null"); } - /** - * - */ @Test public void getNoValueIfOptionNameIsUnexpected() { final String value = "Booh!"; @@ -66,9 +58,6 @@ public boolean test(final Object o) { assertThat(underTest.getValue()).isEmpty(); } - /** - * - */ @Test public void optionValueTypeDiffersFromExpectedType() { final boolean value = false; @@ -79,9 +68,6 @@ public void optionValueTypeDiffersFromExpectedType() { .withCauseInstanceOf(ClassCastException.class); } - /** - * - */ @Test public void optionValueIsExpected() { final JsonFieldSelector fieldSelector = JsonFactory.newFieldSelector("thingId,attributes,features/foo"); diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/FilterOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/FilterOptionVisitorTest.java index adee5881..a3f3e115 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/FilterOptionVisitorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/FilterOptionVisitorTest.java @@ -27,17 +27,12 @@ public final class FilterOptionVisitorTest { private FilterOptionVisitor underTest = null; - /** - * - */ + @Before public void setUp() { underTest = new FilterOptionVisitor(); } - /** - * - */ @Test public void tryToVisitNullOption() { assertThatExceptionOfType(NullPointerException.class) @@ -46,9 +41,6 @@ public void tryToVisitNullOption() { .withMessageContaining("null"); } - /** - * - */ @Test public void getNoValueIfOptionNameIsUnexpected() { final String value = "Booh!"; @@ -64,9 +56,6 @@ public boolean test(final Object o) { assertThat(underTest.getValue()).isEmpty(); } - /** - * - */ @Test public void optionValueTypeDiffersFromExpectedType() { final boolean value = false; @@ -77,9 +66,6 @@ public void optionValueTypeDiffersFromExpectedType() { .withCauseInstanceOf(ClassCastException.class); } - /** - * - */ @Test public void optionValueIsExpected() { final CharSequence filter = "gt(attributes/foo,42)"; diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/NamespacesOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/NamespacesOptionVisitorTest.java index c60f0d3f..6bbce8a6 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/NamespacesOptionVisitorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/NamespacesOptionVisitorTest.java @@ -29,17 +29,12 @@ public final class NamespacesOptionVisitorTest { private NamespacesOptionVisitor underTest = null; - /** - * - */ + @Before public void setUp() { underTest = new NamespacesOptionVisitor(); } - /** - * - */ @Test public void tryToVisitNullOption() { assertThatExceptionOfType(NullPointerException.class) @@ -48,9 +43,6 @@ public void tryToVisitNullOption() { .withMessageContaining("null"); } - /** - * - */ @Test public void getNoValueIfOptionNameIsUnexpected() { final String value = "Booh!"; @@ -66,9 +58,6 @@ public boolean test(final Object o) { assertThat(underTest.getValue()).isEmpty(); } - /** - * - */ @Test public void optionValueTypeDiffersFromExpectedType() { final String value = "Booh!"; @@ -79,9 +68,6 @@ public void optionValueTypeDiffersFromExpectedType() { .withCauseInstanceOf(ClassCastException.class); } - /** - * - */ @Test public void optionValueIsExpected() { final Iterable namespaces = Arrays.asList("one", "two", "three"); diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/OptionsValidatorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/OptionsValidatorTest.java index daee4627..ae912e70 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/OptionsValidatorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/OptionsValidatorTest.java @@ -29,25 +29,17 @@ public final class OptionsValidatorTest { private OptionsValidator underTest = null; - /** - * - */ + @Before public void setUp() { underTest = new OptionsValidator(); } - /** - * - */ @Test public void assertImmutability() { assertInstancesOf(OptionsValidator.class, areImmutable()); } - /** - * - */ @Test public void allOptionsHaveDifferentNames() { final Option responseRequiredOption = createOptionMock(OptionName.Modify.RESPONSE_REQUIRED, true); @@ -56,9 +48,6 @@ public void allOptionsHaveDifferentNames() { underTest.accept(options); } - /** - * - */ @Test public void twoOptionsHaveSameName() { final Option firstOption = createOptionMock(OptionName.Modify.RESPONSE_REQUIRED, false); diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/ResponseRequiredOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/ResponseRequiredOptionVisitorTest.java index 64a100ed..421f11b4 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/ResponseRequiredOptionVisitorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/ResponseRequiredOptionVisitorTest.java @@ -27,17 +27,12 @@ public final class ResponseRequiredOptionVisitorTest { private ResponseRequiredOptionVisitor underTest = null; - /** - * - */ + @Before public void setUp() { underTest = new ResponseRequiredOptionVisitor(); } - /** - * - */ @Test public void tryToVisitNullOption() { assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> underTest.visit(null)) @@ -45,9 +40,6 @@ public void tryToVisitNullOption() { .withMessageContaining("null"); } - /** - * - */ @Test public void getNoValueIfOptionNameIsUnexpected() { final String value = "Booh!"; @@ -63,9 +55,6 @@ public boolean test(final Object o) { assertThat(underTest.getValue()).isEmpty(); } - /** - * - */ @Test public void optionValueTypeDiffersFromExpectedType() { final String value = "Booh!"; @@ -76,9 +65,6 @@ public void optionValueTypeDiffersFromExpectedType() { .withCauseInstanceOf(ClassCastException.class); } - /** - * - */ @Test public void optionValueIsExpected() { final boolean responseRequired = false; diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/UserProvidedOptionsTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/UserProvidedOptionsTest.java index fe7576cf..97104da3 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/UserProvidedOptionsTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/UserProvidedOptionsTest.java @@ -44,27 +44,19 @@ public final class UserProvidedOptionsTest { private Option[] options = null; private UserProvidedOptions underTest = null; - /** - * - */ + @Before public void setUp() { options = new Option[]{responseRequiredOptionMock}; underTest = UserProvidedOptions.of(options); } - /** - * - */ @Test public void assertImmutability() { assertInstancesOf(UserProvidedOptions.class, areImmutable(), provided(Option.class).isAlsoImmutable(), assumingFields("options").areSafelyCopiedUnmodifiableCollectionsWithImmutableElements()); } - /** - * - */ @Test public void tryToCreateInstanceWithNullOptionArray() { assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> UserProvidedOptions.of(null)) @@ -72,9 +64,6 @@ public void tryToCreateInstanceWithNullOptionArray() { .withMessageContaining("null"); } - /** - * - */ @Test public void tryToAcceptNullVisitor() { assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> underTest.accept(null)) @@ -82,9 +71,6 @@ public void tryToAcceptNullVisitor() { .withMessageContaining("null"); } - /** - * - */ @Test public void visitorIsProvidedWithAllOptions() { final OptionVisitor>> visitor = new OptionCollectingVisitor(); @@ -93,9 +79,6 @@ public void visitorIsProvidedWithAllOptions() { assertThat(visitor.getValue()).contains(Arrays.asList(options)); } - /** - * - */ @Test public void visitorIsFinishedAfterFirstOption() { final OptionVisitor>> visitor = new OptionCollectingVisitor(1); From f26f068aa6817cc0b085b9ae4d1af973f0766dbc Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Mon, 6 Apr 2020 11:12:31 +0200 Subject: [PATCH 09/23] Issue eclipse/ditto#611: enhanced Ditto Java client by adding the possibility to specify DittoHeaders as Options * supported handling "Acknowledgements" CommandResponses and extract the "twin-persisted" part of them interpreting them as "normal" CommandResponse * renamed sendSignal() to emitSignal() in MessagingProvider to use the same term as in search feature branch Signed-off-by: Thomas Jaeckle --- .../client/internal/CommonManagementImpl.java | 10 +- .../client/internal/DefaultDittoClient.java | 50 ++++----- .../internal/OutgoingMessageFactory.java | 7 +- .../ditto/client/internal/SendTerminator.java | 100 ++++++++++++++++-- .../client/messaging/MessagingProvider.java | 8 +- .../internal/WebSocketMessagingProvider.java | 7 +- .../eclipse/ditto/client/options/Options.java | 18 +++- .../internal/DittoHeadersOptionVisitor.java | 42 ++++++++ .../options/internal/OptionsEvaluator.java | 10 ++ .../client/internal/SendTerminatorTest.java | 3 +- .../messaging/mock/MockMessagingProvider.java | 2 +- .../ConsumptionOptionsEvaluatorTest.java | 79 ++++++++++++++ .../DittoHeadersOptionVisitorTest.java | 81 ++++++++++++++ .../ExtraFieldsOptionVisitorTest.java | 3 +- .../internal/GlobalOptionsEvaluatorTest.java | 83 +++++++++++++++ ...t.java => ModifyOptionsEvaluatorTest.java} | 8 +- 16 files changed, 453 insertions(+), 58 deletions(-) create mode 100644 java/src/main/java/org/eclipse/ditto/client/options/internal/DittoHeadersOptionVisitor.java create mode 100644 java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumptionOptionsEvaluatorTest.java create mode 100644 java/src/test/java/org/eclipse/ditto/client/options/internal/DittoHeadersOptionVisitorTest.java create mode 100644 java/src/test/java/org/eclipse/ditto/client/options/internal/GlobalOptionsEvaluatorTest.java rename java/src/test/java/org/eclipse/ditto/client/options/internal/{ConsumeOptionsEvaluatorTest.java => ModifyOptionsEvaluatorTest.java} (98%) diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java index ce5452a3..c912e177 100755 --- a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java @@ -58,6 +58,7 @@ import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.model.things.ThingsModelFactory; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.base.WithOptionalEntity; import org.eclipse.ditto.signals.commands.things.modify.CreateThing; import org.eclipse.ditto.signals.commands.things.modify.DeleteThing; import org.eclipse.ditto.signals.commands.things.query.RetrieveThings; @@ -365,8 +366,9 @@ private CompletableFuture processCreate(final Thing thing, @Nullable fina return new SendTerminator(messagingProvider, responseForwarder, channel, command) .applyModify(response -> { - if (response != null) { - return ThingsModelFactory.newThing(response.getEntity(response.getImplementedSchemaVersion()) + if (response instanceof WithOptionalEntity) { + return ThingsModelFactory.newThing( + ((WithOptionalEntity) response).getEntity(response.getImplementedSchemaVersion()) .orElse(JsonFactory.nullObject()).asObject()); } else { return null; @@ -436,8 +438,8 @@ private CompletableFuture> processPut(final Thing thing, @Nullab return new SendTerminator>(messagingProvider, responseForwarder, channel, outgoingMessageFactory.putThing(thing, initialPolicy, options)).applyModify(response -> { - if (response != null) { - return response.getEntity(response.getImplementedSchemaVersion()) + if (response instanceof WithOptionalEntity) { + return ((WithOptionalEntity) response).getEntity(response.getImplementedSchemaVersion()) .map(JsonValue::asObject) .map(ThingsModelFactory::newThing); } else { diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/DefaultDittoClient.java b/java/src/main/java/org/eclipse/ditto/client/internal/DefaultDittoClient.java index b5bd0291..6f57ac0d 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/DefaultDittoClient.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/DefaultDittoClient.java @@ -272,21 +272,21 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e -> MessageFormat.format(THING_PATTERN, e.getThingEntityId()), (e, extra) -> new ImmutableThingChange(e.getThingEntityId(), ChangeAction.CREATED, e.getThing(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, ThingModified.TYPE, ThingModified.class, e -> MessageFormat.format(THING_PATTERN, e.getThingEntityId()), (e, extra) -> new ImmutableThingChange(e.getThingEntityId(), ChangeAction.UPDATED, e.getThing(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, ThingDeleted.TYPE, ThingDeleted.class, e -> MessageFormat.format(THING_PATTERN, e.getThingEntityId()), (e, extra) -> new ImmutableThingChange(e.getThingEntityId(), ChangeAction.DELETED, null, e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); /* @@ -299,7 +299,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), e.getAccessControlList().toJson(e.getImplementedSchemaVersion()), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AclEntryCreated.TYPE, AclEntryCreated.class, @@ -309,7 +309,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), e.getAclEntry().toJson(e.getImplementedSchemaVersion()), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AclEntryModified.TYPE, AclEntryModified.class, @@ -319,7 +319,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), e.getAclEntry().toJson(e.getImplementedSchemaVersion()), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AclEntryDeleted.TYPE, AclEntryDeleted.class, @@ -329,7 +329,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), null, e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); /* @@ -341,7 +341,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), e.getCreatedAttributes(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AttributesModified.TYPE, AttributesModified.class, @@ -350,7 +350,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), e.getModifiedAttributes(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AttributesDeleted.TYPE, AttributesDeleted.class, @@ -359,7 +359,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), null, e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); /* @@ -372,7 +372,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getAttributePointer(), e.getAttributeValue(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal)); + messagingProvider::emitSignal)); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AttributeModified.TYPE, AttributeModified.class, e -> MessageFormat.format(ATTRIBUTE_PATTERN, e.getThingEntityId(), @@ -381,7 +381,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getAttributePointer(), e.getAttributeValue(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal)); + messagingProvider::emitSignal)); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, AttributeDeleted.TYPE, AttributeDeleted.class, e -> MessageFormat.format(ATTRIBUTE_PATTERN, e.getThingEntityId(), @@ -390,7 +390,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getAttributePointer(), null, e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal)); + messagingProvider::emitSignal)); /* * Features @@ -401,7 +401,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getFeatures(), JsonPointer.empty(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturesModified.TYPE, FeaturesModified.class, @@ -410,7 +410,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getFeatures(), JsonPointer.empty(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturesDeleted.TYPE, FeaturesDeleted.class, @@ -419,7 +419,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b null, JsonPointer.empty(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); /* @@ -431,7 +431,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getFeature(), JsonPointer.empty(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeatureModified.TYPE, FeatureModified.class, @@ -440,7 +440,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getFeature(), JsonPointer.empty(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeatureDeleted.TYPE, FeatureDeleted.class, @@ -449,7 +449,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b null, JsonPointer.empty(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); /* @@ -463,7 +463,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), e.getProperties().toJson(e.getImplementedSchemaVersion()), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturePropertiesModified.TYPE, @@ -474,7 +474,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), e.getProperties().toJson(e.getImplementedSchemaVersion()), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturePropertiesDeleted.TYPE, @@ -485,7 +485,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b JsonPointer.empty(), null, e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); /* @@ -499,7 +499,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getPropertyPointer(), e.getPropertyValue(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturePropertyModified.TYPE, @@ -510,7 +510,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getPropertyPointer(), e.getPropertyValue(), e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); SelectorUtil.addHandlerForThingEvent(LOGGER, bus, FeaturePropertyDeleted.TYPE, @@ -521,7 +521,7 @@ private static void registerKeyBasedHandlersForIncomingEvents(final PointerBus b e.getPropertyPointer(), null, e.getRevision(), e.getTimestamp().orElse(null), extra, e.getDittoHeaders(), - messagingProvider::sendSignal) + messagingProvider::emitSignal) ); } diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/OutgoingMessageFactory.java b/java/src/main/java/org/eclipse/ditto/client/internal/OutgoingMessageFactory.java index d727b17d..3ce5bcaf 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/OutgoingMessageFactory.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/OutgoingMessageFactory.java @@ -498,10 +498,13 @@ public Message sendMessage(final MessageSerializerRegistry registry, fina } private DittoHeaders buildDittoHeaders(final boolean allowExists, final Option... options) { + final OptionsEvaluator.Global global = OptionsEvaluator.forGlobalOptions(options); final OptionsEvaluator.Modify modify = OptionsEvaluator.forModifyOptions(options); - final DittoHeadersBuilder headersBuilder = DittoHeaders.newBuilder() - .correlationId(UUID.randomUUID().toString()) + final DittoHeaders additionalHeaders = global.getDittoHeaders().orElse(DittoHeaders.empty()); + final DittoHeadersBuilder headersBuilder = DittoHeaders.newBuilder(additionalHeaders) + .correlationId(additionalHeaders.getCorrelationId() + .orElseGet(() -> UUID.randomUUID().toString())) .schemaVersion(jsonSchemaVersion) .responseRequired(modify.isResponseRequired().orElse(true)); modify.exists().ifPresent(exists -> { diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/SendTerminator.java b/java/src/main/java/org/eclipse/ditto/client/internal/SendTerminator.java index 4a5b2c43..d683e5e0 100755 --- a/java/src/main/java/org/eclipse/ditto/client/internal/SendTerminator.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/SendTerminator.java @@ -18,13 +18,25 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Function; +import java.util.function.Predicate; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.eclipse.ditto.client.messaging.MessagingProvider; +import org.eclipse.ditto.json.JsonField; +import org.eclipse.ditto.json.JsonObject; +import org.eclipse.ditto.json.JsonPointer; +import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.DittoAcknowledgementLabel; +import org.eclipse.ditto.model.base.common.HttpStatusCode; import org.eclipse.ditto.model.base.headers.DittoHeaders; +import org.eclipse.ditto.model.base.json.JsonSchemaVersion; import org.eclipse.ditto.model.messages.Message; +import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; +import org.eclipse.ditto.signals.acks.base.Acknowledgements; import org.eclipse.ditto.signals.commands.base.Command; import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.commands.policies.PolicyCommand; @@ -129,19 +141,35 @@ public void send() { /** * Applies the {@code command} of this SendTerminator with "modify" behavior - expecting a {@link - * ThingModifyCommandResponse} as result and returning a Future of the type {@code }. + * CommandResponse} as result and returning a Future of the type {@code }. * * @param function the function to apply to extract an instance of type {@code } from the returned * {@link ThingModifyCommandResponse}. * @return a CompletableFuture of type {@code }. * @throws NullPointerException if {@code function} is {@code null}. */ - public CompletableFuture applyModify(final Function, T> function) { - final CompletableFuture intermediaryResult = createIntermediaryResult(function); + public CompletableFuture applyModify(final Function function) { + checkNotNull(function, "function"); + final CompletableFuture intermediaryResult = createIntermediaryResult(); LOGGER.trace("Sending modify command <{}>.", command); messagingProvider.sendCommand(command, channel); - return intermediaryResult.thenApply(tcr -> (ThingModifyCommandResponse) tcr).thenApply(function); + return intermediaryResult.thenApply(result -> { + // also handle Acknowledgements which are a CommandResponse as well: + if (result instanceof Acknowledgements) { + // from the "twin-persisted" acknowledgement, create the actual CommandResponse and feed it back + return ((Acknowledgements) result).stream() + .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.PERSISTED)) + .findFirst() + .map(this::createThingModifyCommandResponseFromAcknowledgement) + .map(signal -> (CommandResponse) signal) + .orElseThrow(() -> new IllegalStateException("Didn't receive an Acknowledgement for label '" + + DittoAcknowledgementLabel.PERSISTED + "'. Please make sure to always request the '" + + DittoAcknowledgementLabel.PERSISTED + "' Acknowledgement if you need to process the " + + "response in the client.")); + } + return result; + }).thenApply(function); } /** @@ -155,16 +183,16 @@ public CompletableFuture applyModify(final Function applyModifyPolicy(final Function, T> function) { - final CompletableFuture intermediaryResult = createIntermediaryResult(function); + checkNotNull(function, "function"); + final CompletableFuture intermediaryResult = createIntermediaryResult(); LOGGER.trace("Sending modify command <{}>.", command); messagingProvider.sendCommand(command, channel); return intermediaryResult.thenApply(pcr -> (PolicyModifyCommandResponse) pcr).thenApply(function); } - private CompletableFuture createIntermediaryResult(final Function, ?> function) { + private CompletableFuture createIntermediaryResult() { checkNotNull(command, COMMAND_ARGUMENT_NAME); - checkNotNull(function, "function"); final CompletableFuture intermediaryResult = new CompletableFuture<>(); @@ -192,7 +220,7 @@ private CompletableFuture createIntermediaryResult(final Functi public CompletableFuture applyVoid() { // The CompletableFuture is used to wait for a response even though the response itself is not regarded in // this case. - final CompletableFuture intermediaryResult = createIntermediaryResult(cr -> null); + final CompletableFuture intermediaryResult = createIntermediaryResult(); LOGGER.trace("Sending void command <{}>.", command); messagingProvider.sendCommand(command, channel); @@ -209,7 +237,8 @@ public CompletableFuture applyVoid() { * @throws NullPointerException if {@code function} is {@code null}. */ public CompletableFuture applyView(final Function, T> function) { - final CompletableFuture result = createIntermediaryResult(function); + checkNotNull(function, "function"); + final CompletableFuture result = createIntermediaryResult(); LOGGER.trace("Sending view command <{}>.", command); messagingProvider.sendCommand(command, channel); @@ -227,11 +256,62 @@ public CompletableFuture applyView(final Function applyViewWithPolicyResponse(final Function, T> function) { - final CompletableFuture result = createIntermediaryResult(function); + checkNotNull(function, "function"); + final CompletableFuture result = createIntermediaryResult(); LOGGER.trace("Sending view command <{}>.", command); messagingProvider.sendCommand(command, channel); return result.thenApply(tcr -> (PolicyQueryCommandResponse) tcr).thenApply(function); } + private ThingModifyCommandResponse createThingModifyCommandResponseFromAcknowledgement( + final Acknowledgement ack) { + return new ThingModifyCommandResponse() { + @Override + public JsonPointer getResourcePath() { + return command.getResourcePath(); + } + + @Override + public String getType() { + return command.getType().replace(".commands", ".responses"); + } + + @Nonnull + @Override + public String getManifest() { + return getType(); + } + + @Override + public ThingId getThingEntityId() { + return (ThingId) ack.getEntityId(); + } + + @Override + public DittoHeaders getDittoHeaders() { + return ack.getDittoHeaders(); + } + + @Override + public Optional getEntity(final JsonSchemaVersion schemaVersion) { + return ack.getEntity(schemaVersion); + } + + @Override + public ThingModifyCommandResponse setDittoHeaders(final DittoHeaders dittoHeaders) { + return this; + } + + @Override + public HttpStatusCode getStatusCode() { + return ack.getStatusCode(); + } + + @Override + public JsonObject toJson(final JsonSchemaVersion schemaVersion, final Predicate predicate) { + return JsonObject.empty(); + } + }; + } } diff --git a/java/src/main/java/org/eclipse/ditto/client/messaging/MessagingProvider.java b/java/src/main/java/org/eclipse/ditto/client/messaging/MessagingProvider.java index 3e9aa2a0..971fdad4 100644 --- a/java/src/main/java/org/eclipse/ditto/client/messaging/MessagingProvider.java +++ b/java/src/main/java/org/eclipse/ditto/client/messaging/MessagingProvider.java @@ -70,10 +70,12 @@ public interface MessagingProvider { CompletableFuture sendAdaptable(Adaptable adaptable); /** - * TODO TJ remove again after search branch was merged - this should be easier then! - * @param signal + * Emit a Signal message in a fire-and-forget manner. The signal is translated to an adaptable before emitting. + * + * @param signal the Signal to emit. + * @since 1.1.0 */ - void sendSignal(Signal signal); + void emitSignal(Signal signal); /** * Send message using the underlying connection. diff --git a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java index b84bc7ab..636e9d89 100644 --- a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java +++ b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java @@ -80,6 +80,7 @@ import org.eclipse.ditto.protocoladapter.ProtocolFactory; import org.eclipse.ditto.protocoladapter.TopicPath; import org.eclipse.ditto.protocoladapter.UnknownCommandException; +import org.eclipse.ditto.signals.acks.base.Acknowledgements; import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.commands.base.Command; import org.eclipse.ditto.signals.commands.base.CommandResponse; @@ -362,7 +363,7 @@ private static ExecutorService createConnectionExecutor() { @Override public void send(final Message message, final TopicPath.Channel channel) { - final DittoHeadersBuilder headersBuilder = DittoHeaders.newBuilder(); + final DittoHeadersBuilder headersBuilder = DittoHeaders.newBuilder(); final Optional optionalCorrelationId = message.getCorrelationId(); optionalCorrelationId.ifPresent(headersBuilder::correlationId); final DittoHeaders dittoHeaders = headersBuilder.build(); @@ -500,7 +501,7 @@ public CompletableFuture sendAdaptable(final Adaptable adaptable) { } @Override - public void sendSignal(final Signal signal) { + public void emitSignal(final Signal signal) { try { final Signal adjustedSignal = signal.setDittoHeaders(adjustHeadersForLive(signal)); final Adaptable adaptable = protocolAdapter.toAdaptable(adjustedSignal); @@ -950,6 +951,8 @@ private void handleTwinMessage(final String message, final CharSequence correlat cre.getClass().getSimpleName(), cre.getMessage(), description); } commandResponseConsumer.accept((ThingCommandResponse) signal); + } else if (signal instanceof Acknowledgements) { + commandResponseConsumer.accept((Acknowledgements) signal); } else if (signal instanceof ThingEvent) { LOGGER.debug("Client <{}>: Received TWIN Event JSON: {}", sessionId, message); handleThingEvent(correlationId, (ThingEvent) signal, TwinImpl.CONSUME_TWIN_EVENTS_HANDLER, diff --git a/java/src/main/java/org/eclipse/ditto/client/options/Options.java b/java/src/main/java/org/eclipse/ditto/client/options/Options.java index 93d4fb82..4db14bc5 100755 --- a/java/src/main/java/org/eclipse/ditto/client/options/Options.java +++ b/java/src/main/java/org/eclipse/ditto/client/options/Options.java @@ -15,9 +15,10 @@ import java.util.Arrays; import org.eclipse.ditto.client.management.CommonManagement; +import org.eclipse.ditto.json.JsonFieldSelector; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.policies.PolicyId; import org.eclipse.ditto.model.things.ThingId; -import org.eclipse.ditto.json.JsonFieldSelector; /** * This utility class allows to create {@link Option}s with custom values the Ditto Client is aware of. @@ -30,6 +31,21 @@ private Options() { throw new AssertionError(); } + /** + * Creates an option for specifying additional/custom DittoHeaders to send along together with any command/message + * accepting options. + *

+ * DittoHeader passed in here will be overwritten by more specific {@link Options}, when specified. + *

+ * + * @param dittoHeaders the additional DittoHeaders to send along with an operation. + * @return the new option. + * @since 1.1.0 + */ + public static Option dittoHeaders(final DittoHeaders dittoHeaders) { + return DefaultOption.newInstance(OptionName.Global.DITTO_HEADERS, dittoHeaders); + } + /** * The Modify class provides static factory methods for creating Options which are related to modifying operations. * diff --git a/java/src/main/java/org/eclipse/ditto/client/options/internal/DittoHeadersOptionVisitor.java b/java/src/main/java/org/eclipse/ditto/client/options/internal/DittoHeadersOptionVisitor.java new file mode 100644 index 00000000..09133db9 --- /dev/null +++ b/java/src/main/java/org/eclipse/ditto/client/options/internal/DittoHeadersOptionVisitor.java @@ -0,0 +1,42 @@ +/* + * 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 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.client.options.internal; + +import javax.annotation.concurrent.ThreadSafe; + +import org.eclipse.ditto.client.options.Option; +import org.eclipse.ditto.client.options.OptionName; +import org.eclipse.ditto.model.base.headers.DittoHeaders; + +/** + * This visitor fetches and provides the value as {@code DittoHeaders} for the option with name + * {@link OptionName.Global#DITTO_HEADERS} from the user provided options. + * + * @since 1.1.0 + */ +@ThreadSafe +final class DittoHeadersOptionVisitor extends AbstractOptionVisitor { + + /** + * Constructs a new {@code DittoHeadersOptionVisitor} object. + */ + DittoHeadersOptionVisitor() { + super(OptionName.Global.DITTO_HEADERS); + } + + @Override + protected DittoHeaders getValueFromOption(final Option option) { + return option.getValueAs(DittoHeaders.class); + } + +} diff --git a/java/src/main/java/org/eclipse/ditto/client/options/internal/OptionsEvaluator.java b/java/src/main/java/org/eclipse/ditto/client/options/internal/OptionsEvaluator.java index eb382132..16a520fb 100644 --- a/java/src/main/java/org/eclipse/ditto/client/options/internal/OptionsEvaluator.java +++ b/java/src/main/java/org/eclipse/ditto/client/options/internal/OptionsEvaluator.java @@ -18,6 +18,7 @@ import org.eclipse.ditto.client.options.Option; import org.eclipse.ditto.json.JsonFieldSelector; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.policies.PolicyId; import org.eclipse.ditto.model.things.ThingId; @@ -99,6 +100,15 @@ private Global() { super(); } + /** + * Returns the DittoHeaders to send along for commands/messages to the backend. + * + * @return the DittoHeaders to send along for commands/messages to the backend. + * @since 1.1.0 + */ + public Optional getDittoHeaders() { + return getValue(new DittoHeadersOptionVisitor()); + } } /** diff --git a/java/src/test/java/org/eclipse/ditto/client/internal/SendTerminatorTest.java b/java/src/test/java/org/eclipse/ditto/client/internal/SendTerminatorTest.java index 9a5318f5..1149bc50 100644 --- a/java/src/test/java/org/eclipse/ditto/client/internal/SendTerminatorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/internal/SendTerminatorTest.java @@ -23,6 +23,7 @@ import org.eclipse.ditto.model.messages.Message; import org.eclipse.ditto.model.policies.Label; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.commands.policies.PolicyCommandResponse; import org.eclipse.ditto.signals.commands.policies.modify.DeletePolicyEntryResponse; import org.eclipse.ditto.signals.commands.policies.modify.PolicyModifyCommand; @@ -101,7 +102,7 @@ public void sendModifyCommandWithResponseRequiredAndHandleResponse() { final SendTerminator underTest = new SendTerminator<>(messagingProvider, responseForwarder, channel, thingModifyCommand); - final CompletableFuture promise = underTest.applyModify(ThingCommandResponse::getName); + final CompletableFuture promise = underTest.applyModify(Signal::getName); final boolean isPromiseDoneBeforeBeingHandled = promise.isDone(); responseForwarder.handle(commandResponse); diff --git a/java/src/test/java/org/eclipse/ditto/client/messaging/mock/MockMessagingProvider.java b/java/src/test/java/org/eclipse/ditto/client/messaging/mock/MockMessagingProvider.java index 3183aab0..67a7e951 100644 --- a/java/src/test/java/org/eclipse/ditto/client/messaging/mock/MockMessagingProvider.java +++ b/java/src/test/java/org/eclipse/ditto/client/messaging/mock/MockMessagingProvider.java @@ -115,7 +115,7 @@ public CompletableFuture sendAdaptable(final Adaptable adaptable) { } @Override - public void sendSignal(final Signal signal) { + public void emitSignal(final Signal signal) { // ignore } diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumptionOptionsEvaluatorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumptionOptionsEvaluatorTest.java new file mode 100644 index 00000000..1d45a575 --- /dev/null +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumptionOptionsEvaluatorTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 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 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.client.options.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mutabilitydetector.unittesting.AllowedReason.provided; +import static org.mutabilitydetector.unittesting.MutabilityAssert.assertInstancesOf; +import static org.mutabilitydetector.unittesting.MutabilityMatchers.areImmutable; + +import org.eclipse.ditto.client.options.Option; +import org.eclipse.ditto.client.options.Options; +import org.eclipse.ditto.json.JsonFieldSelector; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * Unit test for {@link OptionsEvaluator.Consumption}. + */ +@RunWith(MockitoJUnitRunner.class) +public final class ConsumptionOptionsEvaluatorTest { + + private static final Option EXTRA_FIELDS = Options.Consumption.extraFields( + JsonFieldSelector.newInstance("foo/bar")); + + private OptionsEvaluator.Consumption underTest = null; + + + @Before + public void setUp() { + final Option[] options = new Option[]{EXTRA_FIELDS}; + underTest = OptionsEvaluator.forConsumptionOptions(options); + } + + @Test + public void assertImmutability() { + assertInstancesOf(OptionsEvaluator.Consumption.class, areImmutable(), + provided(OptionsEvaluator.class).isAlsoImmutable()); + } + + @Test + public void tryToCreateInstanceWithNullOptions() { + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> OptionsEvaluator.forConsumptionOptions(null)) + .withMessage("The options must not be null!"); + } + + @Test + public void createInstanceWithEmptyOptions() { + final OptionsEvaluator.Consumption underTest = OptionsEvaluator.forConsumptionOptions(new Option[0]); + + assertThat(underTest).isNotNull(); + } + + @Test + public void getResponseTimeoutReturnsExpectedIfProvided() { + assertThat(underTest.getExtraFields()).contains(EXTRA_FIELDS.getValue()); + } + + @Test + public void getResponseTimeoutReturnsEmptyOptionalIfNotProvided() { + final Option[] options = new Option[]{}; + underTest = OptionsEvaluator.forConsumptionOptions(options); + + assertThat(underTest.getExtraFields()).isEmpty(); + } + +} diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/DittoHeadersOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/DittoHeadersOptionVisitorTest.java new file mode 100644 index 00000000..2f44cea4 --- /dev/null +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/DittoHeadersOptionVisitorTest.java @@ -0,0 +1,81 @@ +/* + * 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 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.client.options.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.eclipse.ditto.client.options.internal.MockOptionFactory.createOptionMock; + +import org.eclipse.ditto.client.options.OptionName; +import org.eclipse.ditto.model.base.headers.DittoHeaders; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit test for {@link DittoHeadersOptionVisitor}. + */ +public final class DittoHeadersOptionVisitorTest { + + private DittoHeadersOptionVisitor underTest = null; + + + @Before + public void setUp() { + underTest = new DittoHeadersOptionVisitor(); + } + + @Test + public void tryToVisitNullOption() { + assertThatExceptionOfType(NullPointerException.class) + .isThrownBy(() -> underTest.visit(null)) + .withMessageContaining("option to be visited") + .withMessageContaining("null"); + } + + @Test + public void getNoValueIfOptionNameIsUnexpected() { + final String value = "Booh!"; + + final boolean isFinished = underTest.visit(createOptionMock(new OptionName() { + @Override + public boolean test(final Object o) { + return false; + } + }, value)); + + assertThat(isFinished).isFalse(); + assertThat(underTest.getValue()).isEmpty(); + } + + @Test + public void optionValueTypeDiffersFromExpectedType() { + final boolean value = false; + + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> underTest.visit(createOptionMock(OptionName.Global.DITTO_HEADERS, value))) + .withMessage(String.format("The option value <%s> is not of expected type!", value)) + .withCauseInstanceOf(ClassCastException.class); + } + + @Test + public void optionValueIsExpected() { + final DittoHeaders dittoHeaders = DittoHeaders.newBuilder().correlationId("123456").build(); + + final boolean isFinished = + underTest.visit(createOptionMock(OptionName.Global.DITTO_HEADERS, dittoHeaders)); + + assertThat(isFinished).isTrue(); + assertThat(underTest.getValue()).contains(dittoHeaders); + } + +} diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/ExtraFieldsOptionVisitorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/ExtraFieldsOptionVisitorTest.java index 51bf8678..6ee906e0 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/ExtraFieldsOptionVisitorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/ExtraFieldsOptionVisitorTest.java @@ -23,13 +23,12 @@ import org.junit.Test; /** - * Unit test for {@link org.eclipse.ditto.client.options.internal.ExtraFieldsOptionVisitor}. + * Unit test for {@link ExtraFieldsOptionVisitor}. */ public final class ExtraFieldsOptionVisitorTest { private ExtraFieldsOptionVisitor underTest = null; - @Before public void setUp() { underTest = new ExtraFieldsOptionVisitor(); diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/GlobalOptionsEvaluatorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/GlobalOptionsEvaluatorTest.java new file mode 100644 index 00000000..dbb78e21 --- /dev/null +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/GlobalOptionsEvaluatorTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019 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 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.client.options.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mutabilitydetector.unittesting.AllowedReason.provided; +import static org.mutabilitydetector.unittesting.MutabilityAssert.assertInstancesOf; +import static org.mutabilitydetector.unittesting.MutabilityMatchers.areImmutable; + +import java.util.UUID; + +import org.eclipse.ditto.client.options.Option; +import org.eclipse.ditto.client.options.Options; +import org.eclipse.ditto.model.base.headers.DittoHeaders; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * Unit test for {@link OptionsEvaluator.Global}. + */ +@RunWith(MockitoJUnitRunner.class) +public final class GlobalOptionsEvaluatorTest { + + private static final DittoHeaders KNOWN_DITTO_HEADERS = DittoHeaders.newBuilder() + .correlationId(UUID.randomUUID().toString()) + .build(); + private static final Option DITTO_HEADERS_OPTION = Options.dittoHeaders(KNOWN_DITTO_HEADERS); + + private OptionsEvaluator.Global underTest = null; + + + @Before + public void setUp() { + final Option[] options = new Option[]{DITTO_HEADERS_OPTION}; + underTest = OptionsEvaluator.forGlobalOptions(options); + } + + @Test + public void assertImmutability() { + assertInstancesOf(OptionsEvaluator.Global.class, areImmutable(), + provided(OptionsEvaluator.class).isAlsoImmutable()); + } + + @Test + public void tryToCreateInstanceWithNullOptions() { + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> OptionsEvaluator.forGlobalOptions(null)) + .withMessage("The options must not be null!"); + } + + @Test + public void createInstanceWithEmptyOptions() { + final OptionsEvaluator.Global underTest = OptionsEvaluator.forGlobalOptions(new Option[0]); + + assertThat(underTest).isNotNull(); + } + + @Test + public void getResponseTimeoutReturnsExpectedIfProvided() { + assertThat(underTest.getDittoHeaders()).contains(DITTO_HEADERS_OPTION.getValue()); + } + + @Test + public void getResponseTimeoutReturnsEmptyOptionalIfNotProvided() { + final Option[] options = new Option[]{}; + underTest = OptionsEvaluator.forGlobalOptions(options); + + assertThat(underTest.getDittoHeaders()).isEmpty(); + } + +} diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumeOptionsEvaluatorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/ModifyOptionsEvaluatorTest.java similarity index 98% rename from java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumeOptionsEvaluatorTest.java rename to java/src/test/java/org/eclipse/ditto/client/options/internal/ModifyOptionsEvaluatorTest.java index ca4c174d..1a68fdf5 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/ConsumeOptionsEvaluatorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/ModifyOptionsEvaluatorTest.java @@ -29,7 +29,7 @@ * Unit test for {@link OptionsEvaluator.Modify}. */ @RunWith(MockitoJUnitRunner.class) -public final class ConsumeOptionsEvaluatorTest { +public final class ModifyOptionsEvaluatorTest { private static final Option RESPONSE_REQUIRED_OPTION = Options.Modify.responseRequired(false); @@ -42,28 +42,24 @@ public void setUp() { underTest = OptionsEvaluator.forModifyOptions(options); } - @Test public void assertThatOptionsEvaluatorIsImmutable() { assertInstancesOf(OptionsEvaluator.class, areImmutable(), provided(UserProvidedOptions.class).isAlsoImmutable()); } - @Test public void assertImmutability() { assertInstancesOf(OptionsEvaluator.Modify.class, areImmutable(), provided(OptionsEvaluator.class).isAlsoImmutable()); } - @Test public void tryToCreateInstanceWithNullOptions() { assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> OptionsEvaluator.forModifyOptions(null)) .withMessage("The options must not be null!"); } - @Test public void createInstanceWithEmptyOptions() { final OptionsEvaluator.Modify underTest = OptionsEvaluator.forModifyOptions(new Option[0]); @@ -71,13 +67,11 @@ public void createInstanceWithEmptyOptions() { assertThat(underTest).isNotNull(); } - @Test public void getResponseTimeoutReturnsExpectedIfProvided() { assertThat(underTest.isResponseRequired()).contains(RESPONSE_REQUIRED_OPTION.getValue()); } - @Test public void getResponseTimeoutReturnsEmptyOptionalIfNotProvided() { final Option[] options = new Option[]{}; From 320432485ce742fe108d86ca389a8d9150e24903 Mon Sep 17 00:00:00 2001 From: Yufei Cai Date: Fri, 17 Apr 2020 15:59:18 +0200 Subject: [PATCH 10/23] Test Acknowledgements and fix errors discovered therewith. Signed-off-by: Yufei Cai --- .../ditto/client/internal/AbstractHandle.java | 3 +- .../client/internal/CommonManagementImpl.java | 18 ++-- .../ditto/client/DittoClientThingTest.java | 82 +++++++++++++++++++ .../internal/AbstractDittoClientTest.java | 14 ++-- 4 files changed, 103 insertions(+), 14 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java index a36fa7e4..0893994f 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java @@ -32,6 +32,7 @@ import org.eclipse.ditto.protocoladapter.ProtocolFactory; import org.eclipse.ditto.protocoladapter.TopicPath; import org.eclipse.ditto.signals.base.Signal; +import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.commands.base.ErrorResponse; import org.eclipse.ditto.signals.commands.policies.PolicyCommand; import org.eclipse.ditto.signals.commands.policies.PolicyCommandResponse; @@ -137,7 +138,7 @@ protected , S extends PolicyCommandResponse, R> Co * @return future of the result if the expected response arrives or a failed future on error. * Type is {@code CompletionStage} to signify that the future will complete or fail without caller intervention. */ - protected , S extends ThingCommandResponse, R> CompletionStage askThingCommand( + protected , S extends CommandResponse, R> CompletionStage askThingCommand( final T command, final Class expectedResponse, final Function onSuccess) { diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java index e5b75aee..3497a1e1 100755 --- a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java @@ -51,7 +51,6 @@ import org.eclipse.ditto.client.options.Option; import org.eclipse.ditto.client.options.OptionName; import org.eclipse.ditto.client.options.internal.OptionsEvaluator; -import org.eclipse.ditto.json.JsonFactory; import org.eclipse.ditto.json.JsonField; import org.eclipse.ditto.json.JsonFieldSelector; import org.eclipse.ditto.json.JsonObject; @@ -79,7 +78,6 @@ import org.eclipse.ditto.signals.commands.base.Command; import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.commands.things.modify.CreateThing; -import org.eclipse.ditto.signals.commands.things.modify.CreateThingResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteThing; import org.eclipse.ditto.signals.commands.things.modify.DeleteThingResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyThing; @@ -376,7 +374,9 @@ private CompletableFuture processCreate(final Thing thing, @Nullable fina final CreateThing command = outgoingMessageFactory.createThing(thing, initialPolicy, options); - return askThingCommand(command, CreateThingResponse.class, + return this.askThingCommand(command, + // response could be CreateThingResponse or ModifyThingResponse or Acknowledgements. + CommandResponse.class, response -> transformModifyResponse(command, response)) .toCompletableFuture(); } @@ -443,8 +443,8 @@ private CompletableFuture> processPut(final Thing thing, @Nullab final ModifyThing command = outgoingMessageFactory.putThing(thing, initialPolicy, options); return askThingCommand(command, - // response could be either CreateThingResponse or ModifyThingResponse. - ThingModifyCommandResponse.class, + // response could be CreateThingResponse or ModifyThingResponse or Acknowledgements. + CommandResponse.class, response -> Optional.ofNullable(transformModifyResponse(command, response)) ).toCompletableFuture(); } @@ -753,9 +753,11 @@ private Thing transformModifyResponse(final Command command, final CommandRes } if (response instanceof WithOptionalEntity) { - return ThingsModelFactory.newThing( - ((WithOptionalEntity) response).getEntity(response.getImplementedSchemaVersion()) - .orElse(JsonFactory.nullObject()).asObject()); + return ((WithOptionalEntity) response).getEntity(response.getImplementedSchemaVersion()) + .filter(JsonValue::isObject) + .map(JsonValue::asObject) + .map(ThingsModelFactory::newThing) + .orElse(null); } else { return null; } diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java index 15f892fc..26a63cee 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java @@ -20,11 +20,14 @@ import static org.eclipse.ditto.client.TestConstants.Thing.THING_ID_COPY_POLICY; import static org.eclipse.ditto.client.TestConstants.Thing.THING_WITH_INLINE_POLICY; import static org.eclipse.ditto.client.assertions.ClientAssertions.assertThat; +import static org.eclipse.ditto.model.base.acks.AcknowledgementRequest.parseAcknowledgementRequest; +import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import org.assertj.core.api.Assertions; +import org.assertj.core.api.Assumptions; import org.eclipse.ditto.client.internal.AbstractDittoClientThingsTest; import org.eclipse.ditto.client.options.Option; import org.eclipse.ditto.client.options.Options; @@ -32,8 +35,12 @@ import org.eclipse.ditto.json.JsonFactory; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; +import org.eclipse.ditto.model.base.acks.AcknowledgementRequest; import org.eclipse.ditto.model.base.auth.AuthorizationModelFactory; import org.eclipse.ditto.model.base.auth.AuthorizationSubject; +import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.messages.Message; import org.eclipse.ditto.model.messages.MessageDirection; import org.eclipse.ditto.model.messages.MessageHeaders; @@ -44,6 +51,9 @@ import org.eclipse.ditto.model.things.Thing; import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.model.things.ThingsModelFactory; +import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; +import org.eclipse.ditto.signals.acks.base.Acknowledgements; import org.eclipse.ditto.signals.commands.things.modify.CreateThing; import org.eclipse.ditto.signals.commands.things.modify.CreateThingResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteThing; @@ -86,6 +96,34 @@ public void testCreateThing() { expectMsgClass(CreateThing.class).getDittoHeaders())); } + @Test + public void testCreateThingWith2Acknowledgements() { + // skip this test for LIVE - 'twin-persisted' is obligatory + Assumptions.assumeThat(channel).isEqualTo(TopicPath.Channel.TWIN); + + final AcknowledgementLabel label1 = AcknowledgementLabel.of("custom-ack-1"); + final AcknowledgementLabel label2 = AcknowledgementLabel.of("twin-persisted"); + assertEventualCompletion(getManagement() + .create(THING_ID, Options.dittoHeaders(DittoHeaders.newBuilder() + .acknowledgementRequest( + AcknowledgementRequest.of(label1), + AcknowledgementRequest.of(label2)) + .build())) + ); + + final DittoHeaders sentDittoHeaders = expectMsgClass(CreateThing.class).getDittoHeaders(); + reply(Acknowledgements.of( + Arrays.asList( + Acknowledgement.of(label1, THING_ID, HttpStatusCode.OK, DittoHeaders.empty()), + Acknowledgement.of(label2, THING_ID, HttpStatusCode.ACCEPTED, DittoHeaders.empty()) + ), + sentDittoHeaders + )); + + assertThat(sentDittoHeaders.getAcknowledgementRequests()) + .containsExactly(AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)); + } + @Test public void createThingFailsWithExistsOption() { assertThatExceptionOfType(IllegalArgumentException.class) @@ -398,4 +436,48 @@ public void testPutThingWithAllOptionCopyPolicy() { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> getManagement().put(THING, copyPolicy, copyPolicyFromThing)); } + + @Test + public void testPutThingWithoutPolicy() { + assertEventualCompletion(getManagement().put(THING) + .thenAccept(result -> assertThat(result).isEmpty()) + ); + + reply(ModifyThingResponse.modified(THING_ID, expectMsgClass(ModifyThing.class).getDittoHeaders())); + } + + @Test + public void testEventAcknowledgement() { + // Acknowledgements are not implemented for live signals yet + Assumptions.assumeThat(channel).isEqualTo(TopicPath.Channel.TWIN); + + getManagement().startConsumption(); + getManagement().registerForThingChanges("Ackermann", change -> + change.handleAcknowledgementRequests(handles -> + handles.forEach(handle -> handle.acknowledge( + HttpStatusCode.forInt(Integer.parseInt(handle.getAcknowledgementLabel().toString())) + .orElse(HttpStatusCode.EXPECTATION_FAILED) + )) + ) + ); + // expect subscription messages + assertThat(expectMsgClass(String.class)).startsWith("START-SEND-"); + if (channel == TopicPath.Channel.LIVE) { + assertThat(expectMsgClass(String.class)).startsWith("START-SEND-"); + assertThat(expectMsgClass(String.class)).startsWith("START-SEND-"); + } + + reply(ThingDeleted.of(THING_ID, 1L, DittoHeaders.newBuilder() + .channel(channel.name()) + .acknowledgementRequest( + parseAcknowledgementRequest("100"), + parseAcknowledgementRequest("301"), + parseAcknowledgementRequest("403") + ) + .build()) + ); + assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()).isEqualTo(HttpStatusCode.CONTINUE); + assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()).isEqualTo(HttpStatusCode.MOVED_PERMANENTLY); + assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()).isEqualTo(HttpStatusCode.FORBIDDEN); + } } diff --git a/java/src/test/java/org/eclipse/ditto/client/internal/AbstractDittoClientTest.java b/java/src/test/java/org/eclipse/ditto/client/internal/AbstractDittoClientTest.java index f4a76684..60262e0d 100755 --- a/java/src/test/java/org/eclipse/ditto/client/internal/AbstractDittoClientTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/internal/AbstractDittoClientTest.java @@ -109,12 +109,16 @@ protected void expectMsg(final String msg) { protected T expectMsgClass(final Class clazz) { final String nextMessage = messaging.expectEmitted(); - final Signal signal = PROTOCOL_ADAPTER.fromAdaptable( - ProtocolFactory.jsonifiableAdaptableFromJson(JsonObject.of(nextMessage))); - if (clazz.isInstance(signal)) { - return clazz.cast(signal); + if (clazz.isAssignableFrom(String.class)) { + return clazz.cast(nextMessage); } else { - throw new AssertionError("Expect " + clazz + ", got " + signal); + final Signal signal = PROTOCOL_ADAPTER.fromAdaptable( + ProtocolFactory.jsonifiableAdaptableFromJson(JsonObject.of(nextMessage))); + if (clazz.isInstance(signal)) { + return clazz.cast(signal); + } else { + throw new AssertionError("Expect " + clazz + ", got " + signal); + } } } From 9d0b426c30d95680ea0fe88757a0512eaa65dab6 Mon Sep 17 00:00:00 2001 From: Yufei Cai Date: Mon, 20 Apr 2020 10:36:16 +0200 Subject: [PATCH 11/23] Test and fix error response handling. Signed-off-by: Yufei Cai --- .../ditto/client/internal/AbstractHandle.java | 27 +++++++++---------- .../ditto/client/DittoClientPoliciesTest.java | 17 ++++++++++++ .../ditto/client/DittoClientThingTest.java | 19 +++++++++++++ 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java index 0893994f..160bb23e 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java @@ -17,6 +17,7 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.function.Function; import java.util.stream.Collectors; @@ -37,7 +38,6 @@ import org.eclipse.ditto.signals.commands.policies.PolicyCommand; import org.eclipse.ditto.signals.commands.policies.PolicyCommandResponse; import org.eclipse.ditto.signals.commands.things.ThingCommand; -import org.eclipse.ditto.signals.commands.things.ThingCommandResponse; /** * Super class of API handles including common methods for request-response handling. @@ -120,9 +120,7 @@ protected , S extends PolicyCommandResponse, R> Co final Class expectedResponse, final Function onSuccess) { return sendSignalAndExpectResponse(command, expectedResponse, onSuccess, ErrorResponse.class, - errorResponse -> { - throw errorResponse.getDittoRuntimeException(); - }); + ErrorResponse::getDittoRuntimeException); } /** @@ -144,9 +142,7 @@ protected , S extends CommandResponse, R> Completio final Function onSuccess) { final ThingCommand commandWithChannel = setChannel(command, channel); return sendSignalAndExpectResponse(commandWithChannel, expectedResponse, onSuccess, ErrorResponse.class, - errorResponse -> { - throw errorResponse.getDittoRuntimeException(); - }); + ErrorResponse::getDittoRuntimeException); } /** @@ -166,22 +162,25 @@ protected CompletionStage sendSignalAndExpectResponse(final Signal final Class expectedResponseClass, final Function onSuccess, final Class expectedErrorResponseClass, - final Function onError) { + final Function onError) { final CompletionStage responseFuture = messagingProvider.getAdaptableBus() .subscribeOnceForAdaptable(Classification.forCorrelationId(signal), getTimeout()); messagingProvider.emit(signalToJsonString(signal)); - return responseFuture.thenApply(responseAdaptable -> { + final CompletableFuture future = new CompletableFuture<>(); + responseFuture.thenAccept(responseAdaptable -> { final Signal response = signalFromAdaptable(responseAdaptable); - if (expectedResponseClass.isInstance(response)) { - return onSuccess.apply(expectedResponseClass.cast(response)); - } else if (expectedErrorResponseClass.isInstance(response)) { - return onError.apply(expectedErrorResponseClass.cast(response)); + if (expectedErrorResponseClass.isInstance(response)) { + future.completeExceptionally(onError.apply(expectedErrorResponseClass.cast(response))); + } else if (expectedResponseClass.isInstance(response)) { + future.complete(onSuccess.apply(expectedResponseClass.cast(response))); } else { - throw new ClassCastException("Expect " + expectedResponseClass.getSimpleName() + ", got: " + response); + future.completeExceptionally(new ClassCastException( + "Expect " + expectedResponseClass.getSimpleName() + ", got: " + response)); } }); + return future; } /** diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java index 58f49ea6..2675f240 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java @@ -35,6 +35,8 @@ import org.eclipse.ditto.model.policies.Policy; import org.eclipse.ditto.signals.commands.policies.PolicyCommand; import org.eclipse.ditto.signals.commands.policies.PolicyCommandResponse; +import org.eclipse.ditto.signals.commands.policies.PolicyErrorResponse; +import org.eclipse.ditto.signals.commands.policies.exceptions.PolicyNotAccessibleException; import org.eclipse.ditto.signals.commands.policies.modify.CreatePolicy; import org.eclipse.ditto.signals.commands.policies.modify.CreatePolicyResponse; import org.eclipse.ditto.signals.commands.policies.modify.DeletePolicy; @@ -181,6 +183,21 @@ public void testRetrievePolicy() throws Exception { Assertions.assertThat(retrievePolicyResponse).isCompletedWithValue(POLICY); } + @Test + public void testRetrievePolicyFails() { + assertEventualCompletion(client.policies().retrieve(POLICY_ID).handle((response, error) -> { + assertThat(error) + .describedAs("Expect failure with %s, got response=%s, error=%s", + PolicyNotAccessibleException.class.getSimpleName(), response, error) + .isInstanceOf(PolicyNotAccessibleException.class); + return null; + })); + final RetrievePolicy retrievePolicy = expectMsgClass(RetrievePolicy.class); + reply(PolicyErrorResponse.of(PolicyNotAccessibleException.newBuilder(POLICY_ID) + .dittoHeaders(retrievePolicy.getDittoHeaders()) + .build())); + } + @Test(expected = JsonMissingFieldException.class) public void testCreatePolicyWithMissingId() { client.policies().create(JsonFactory.newObject()); diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java index 26a63cee..3069a7d0 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java @@ -40,6 +40,7 @@ import org.eclipse.ditto.model.base.auth.AuthorizationModelFactory; import org.eclipse.ditto.model.base.auth.AuthorizationSubject; import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.base.exceptions.DittoRuntimeException; import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.messages.Message; import org.eclipse.ditto.model.messages.MessageDirection; @@ -54,6 +55,8 @@ import org.eclipse.ditto.protocoladapter.TopicPath; import org.eclipse.ditto.signals.acks.base.Acknowledgement; import org.eclipse.ditto.signals.acks.base.Acknowledgements; +import org.eclipse.ditto.signals.commands.things.ThingErrorResponse; +import org.eclipse.ditto.signals.commands.things.exceptions.ThingPreconditionFailedException; import org.eclipse.ditto.signals.commands.things.modify.CreateThing; import org.eclipse.ditto.signals.commands.things.modify.CreateThingResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteThing; @@ -147,6 +150,22 @@ public void testPutThingWithExistsOptionTrue() { assertOnlyIfMatchHeader(command); } + @Test + public void testPutThingWithUnsatisfiedPrecondition() { + assertEventualCompletion(getManagement().put(THING, Options.Modify.exists(true)) + .handle((response, error) -> { + assertThat(error) + .describedAs("Expect failure with %s, got response=%s, error=%s", + ThingPreconditionFailedException.class.getSimpleName(), response, error) + .isInstanceOf(ThingPreconditionFailedException.class); + return null; + })); + final ModifyThing command = expectMsgClass(ModifyThing.class); + final DittoRuntimeException error = + ThingPreconditionFailedException.newBuilder("if-match", "\"*\"", "").build(); + reply(ThingErrorResponse.of(error, command.getDittoHeaders())); + } + @Test public void testUpdateThing() { assertEventualCompletion(getManagement().update(THING)); From 15672a3af566f66fa3c6d183d9b12c66c0f03ceb Mon Sep 17 00:00:00 2001 From: Yufei Cai Date: Mon, 20 Apr 2020 11:15:58 +0200 Subject: [PATCH 12/23] Re-wrap exceptions from error responses in CompletionException. Signed-off-by: Yufei Cai --- .../ditto/client/internal/AbstractHandle.java | 13 +++++-------- .../ditto/client/DittoClientPoliciesTest.java | 4 +++- .../eclipse/ditto/client/DittoClientThingTest.java | 4 +++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java index 160bb23e..aaa65828 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java @@ -17,7 +17,6 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Map; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.function.Function; import java.util.stream.Collectors; @@ -168,19 +167,17 @@ protected CompletionStage sendSignalAndExpectResponse(final Signal .subscribeOnceForAdaptable(Classification.forCorrelationId(signal), getTimeout()); messagingProvider.emit(signalToJsonString(signal)); - final CompletableFuture future = new CompletableFuture<>(); - responseFuture.thenAccept(responseAdaptable -> { + return responseFuture.thenApply(responseAdaptable -> { final Signal response = signalFromAdaptable(responseAdaptable); if (expectedErrorResponseClass.isInstance(response)) { - future.completeExceptionally(onError.apply(expectedErrorResponseClass.cast(response))); + // extracted runtime exception will be wrapped in CompletionException. + throw onError.apply(expectedErrorResponseClass.cast(response)); } else if (expectedResponseClass.isInstance(response)) { - future.complete(onSuccess.apply(expectedResponseClass.cast(response))); + return onSuccess.apply(expectedResponseClass.cast(response)); } else { - future.completeExceptionally(new ClassCastException( - "Expect " + expectedResponseClass.getSimpleName() + ", got: " + response)); + throw new ClassCastException("Expect " + expectedResponseClass.getSimpleName() + ", got: " + response); } }); - return future; } /** diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java index 2675f240..cd1efad8 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientPoliciesTest.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.function.Function; import org.assertj.core.api.Assertions; @@ -189,7 +190,8 @@ public void testRetrievePolicyFails() { assertThat(error) .describedAs("Expect failure with %s, got response=%s, error=%s", PolicyNotAccessibleException.class.getSimpleName(), response, error) - .isInstanceOf(PolicyNotAccessibleException.class); + .isInstanceOf(CompletionException.class) + .hasCauseInstanceOf(PolicyNotAccessibleException.class); return null; })); final RetrievePolicy retrievePolicy = expectMsgClass(RetrievePolicy.class); diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java index 3069a7d0..90d676d1 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java @@ -23,6 +23,7 @@ import static org.eclipse.ditto.model.base.acks.AcknowledgementRequest.parseAcknowledgementRequest; import java.util.Arrays; +import java.util.concurrent.CompletionException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; @@ -157,7 +158,8 @@ public void testPutThingWithUnsatisfiedPrecondition() { assertThat(error) .describedAs("Expect failure with %s, got response=%s, error=%s", ThingPreconditionFailedException.class.getSimpleName(), response, error) - .isInstanceOf(ThingPreconditionFailedException.class); + .isInstanceOf(CompletionException.class) + .hasCauseInstanceOf(ThingPreconditionFailedException.class); return null; })); final ModifyThing command = expectMsgClass(ModifyThing.class); From df67bf4b4bc47e978d6ce2aa8751a972f1b4d45d Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Mon, 20 Apr 2020 13:15:40 +0200 Subject: [PATCH 13/23] Issue eclipse/ditto#611: review: simplified DittoClientThingTest.testEventAcknowledgement test as `channel` can't be "live" due to assertJ Assumption Signed-off-by: Thomas Jaeckle --- .../java/org/eclipse/ditto/client/DittoClientThingTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java index 90d676d1..3146e1d0 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java @@ -483,10 +483,6 @@ public void testEventAcknowledgement() { ); // expect subscription messages assertThat(expectMsgClass(String.class)).startsWith("START-SEND-"); - if (channel == TopicPath.Channel.LIVE) { - assertThat(expectMsgClass(String.class)).startsWith("START-SEND-"); - assertThat(expectMsgClass(String.class)).startsWith("START-SEND-"); - } reply(ThingDeleted.of(THING_ID, 1L, DittoHeaders.newBuilder() .channel(channel.name()) From 479931474e98f4c397b6297c18ec9d1ad26b8b31 Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Mon, 20 Apr 2020 17:54:32 +0200 Subject: [PATCH 14/23] Issue eclipse/ditto#611: ensure requesting acks is possible for feature + attribute commands as well Signed-off-by: Thomas Jaeckle --- .../ditto/client/internal/AbstractHandle.java | 7 +++- .../client/internal/CommonManagementImpl.java | 38 +++++++++-------- .../internal/FeatureHandleImpl.java | 22 ++++------ .../management/internal/ThingHandleImpl.java | 32 +++++--------- .../client/DittoClientAttributesTest.java | 40 ++++++++++++++++++ .../ditto/client/DittoClientFeaturesTest.java | 42 +++++++++++++++++++ 6 files changed, 128 insertions(+), 53 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java index aaa65828..37635566 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java @@ -31,6 +31,7 @@ import org.eclipse.ditto.protocoladapter.ProtocolAdapter; import org.eclipse.ditto.protocoladapter.ProtocolFactory; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.acks.base.Acknowledgements; import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.commands.base.ErrorResponse; @@ -157,7 +158,7 @@ protected , S extends CommandResponse, R> Completio * @param type of the result. * @return future of the result. */ - protected CompletionStage sendSignalAndExpectResponse(final Signal signal, + protected CompletionStage sendSignalAndExpectResponse(final Signal signal, final Class expectedResponseClass, final Function onSuccess, final Class expectedErrorResponseClass, @@ -174,6 +175,10 @@ protected CompletionStage sendSignalAndExpectResponse(final Signal throw onError.apply(expectedErrorResponseClass.cast(response)); } else if (expectedResponseClass.isInstance(response)) { return onSuccess.apply(expectedResponseClass.cast(response)); + } else if (response instanceof Acknowledgements) { + final CommandResponse commandResponse = CommonManagementImpl + .extractCommandResponseFromAcknowledgements(signal, (Acknowledgements) response); + return onSuccess.apply(expectedResponseClass.cast(commandResponse)); } else { throw new ClassCastException("Expect " + expectedResponseClass.getSimpleName() + ", got: " + response); } diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java index 3497a1e1..4be65268 100755 --- a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java @@ -79,9 +79,7 @@ import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.commands.things.modify.CreateThing; import org.eclipse.ditto.signals.commands.things.modify.DeleteThing; -import org.eclipse.ditto.signals.commands.things.modify.DeleteThingResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyThing; -import org.eclipse.ditto.signals.commands.things.modify.ModifyThingResponse; import org.eclipse.ditto.signals.commands.things.modify.ThingModifyCommandResponse; import org.eclipse.ditto.signals.commands.things.query.RetrieveThings; import org.eclipse.ditto.signals.commands.things.query.RetrieveThingsResponse; @@ -454,7 +452,7 @@ public CompletableFuture update(final Thing thing, final Option... opti argumentNotNull(thing); assertThatThingHasId(thing); - return askThingCommand(outgoingMessageFactory.updateThing(thing, options), ModifyThingResponse.class, + return askThingCommand(outgoingMessageFactory.updateThing(thing, options), CommandResponse.class, this::toVoid).toCompletableFuture(); } @@ -471,7 +469,7 @@ public CompletableFuture delete(final ThingId thingId, final Option... argumentNotNull(thingId); final DeleteThing command = outgoingMessageFactory.deleteThing(thingId, options); - return askThingCommand(command, DeleteThingResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -739,15 +737,7 @@ private Thing transformModifyResponse(final Command command, final CommandRes // also handle Acknowledgements which are a CommandResponse as well: if (result instanceof Acknowledgements) { // from the "twin-persisted" acknowledgement, create the actual CommandResponse and feed it back - response = ((Acknowledgements) result).stream() - .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.PERSISTED)) - .findFirst() - .map(ack -> createThingModifyCommandResponseFromAcknowledgement(command, ack)) - .map(signal -> (CommandResponse) signal) - .orElseThrow(() -> new IllegalStateException("Didn't receive an Acknowledgement for label '" + - DittoAcknowledgementLabel.PERSISTED + "'. Please make sure to always request the '" + - DittoAcknowledgementLabel.PERSISTED + "' Acknowledgement if you need to process the " + - "response in the client.")); + response = extractCommandResponseFromAcknowledgements(command, (Acknowledgements) result); } else { response = result; } @@ -763,19 +753,33 @@ private Thing transformModifyResponse(final Command command, final CommandRes } } - private ThingModifyCommandResponse> + static CommandResponse extractCommandResponseFromAcknowledgements(final Signal signal, + final Acknowledgements result) { + final CommandResponse response; + response = result.stream() + .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.PERSISTED)) + .findFirst() + .map(ack -> createThingModifyCommandResponseFromAcknowledgement(signal, ack)) + .orElseThrow(() -> new IllegalStateException("Didn't receive an Acknowledgement for label '" + + DittoAcknowledgementLabel.PERSISTED + "'. Please make sure to always request the '" + + DittoAcknowledgementLabel.PERSISTED + "' Acknowledgement if you need to process the " + + "response in the client.")); + return response; + } + + private static ThingModifyCommandResponse> createThingModifyCommandResponseFromAcknowledgement( - final Command command, + final Signal signal, final Acknowledgement ack) { return new ThingModifyCommandResponse>() { @Override public JsonPointer getResourcePath() { - return command.getResourcePath(); + return signal.getResourcePath(); } @Override public String getType() { - return command.getType().replace(".commands", ".responses"); + return signal.getType().replace(".commands", ".responses"); } @Nonnull diff --git a/java/src/main/java/org/eclipse/ditto/client/management/internal/FeatureHandleImpl.java b/java/src/main/java/org/eclipse/ditto/client/management/internal/FeatureHandleImpl.java index 39ea1465..ec64ae86 100755 --- a/java/src/main/java/org/eclipse/ditto/client/management/internal/FeatureHandleImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/management/internal/FeatureHandleImpl.java @@ -36,20 +36,14 @@ import org.eclipse.ditto.model.things.FeatureDefinition; import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeature; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatureDefinition; -import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatureDefinitionResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatureProperties; -import org.eclipse.ditto.signals.commands.things.modify.DeleteFeaturePropertiesResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatureProperty; -import org.eclipse.ditto.signals.commands.things.modify.DeleteFeaturePropertyResponse; -import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatureResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyFeatureDefinition; -import org.eclipse.ditto.signals.commands.things.modify.ModifyFeatureDefinitionResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyFeatureProperties; -import org.eclipse.ditto.signals.commands.things.modify.ModifyFeaturePropertiesResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyFeatureProperty; -import org.eclipse.ditto.signals.commands.things.modify.ModifyFeaturePropertyResponse; import org.eclipse.ditto.signals.commands.things.query.RetrieveFeature; import org.eclipse.ditto.signals.commands.things.query.RetrieveFeatureResponse; import org.slf4j.Logger; @@ -127,7 +121,7 @@ public String getFeatureId() { @Override public CompletableFuture delete(final Option... options) { final DeleteFeature command = outgoingMessageFactory.deleteFeature(thingId, featureId, options); - return askThingCommand(command, DeleteFeatureResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -150,14 +144,14 @@ public CompletableFuture setDefinition(final FeatureDefinition featureDefi final Option... options) { final ModifyFeatureDefinition command = outgoingMessageFactory.setFeatureDefinition(thingId, featureId, featureDefinition, options); - return askThingCommand(command, ModifyFeatureDefinitionResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override public CompletableFuture deleteDefinition(final Option... options) { final DeleteFeatureDefinition command = outgoingMessageFactory.deleteFeatureDefinition(thingId, featureId, options); - return askThingCommand(command, DeleteFeatureDefinitionResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -197,28 +191,28 @@ public CompletableFuture putProperty(final JsonPointer path, final JsonVal final ModifyFeatureProperty command = outgoingMessageFactory.setFeatureProperty(thingId, featureId, path, value, options); - return askThingCommand(command, ModifyFeaturePropertyResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override public CompletableFuture setProperties(final JsonObject value, final Option... options) { final ModifyFeatureProperties command = outgoingMessageFactory.setFeatureProperties(thingId, featureId, value, options); - return askThingCommand(command, ModifyFeaturePropertiesResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override public CompletableFuture deleteProperty(final JsonPointer path, final Option... options) { final DeleteFeatureProperty command = outgoingMessageFactory.deleteFeatureProperty(thingId, featureId, path, options); - return askThingCommand(command, DeleteFeaturePropertyResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override public CompletableFuture deleteProperties(final Option... options) { final DeleteFeatureProperties command = outgoingMessageFactory.deleteFeatureProperties(thingId, featureId, options); - return askThingCommand(command, DeleteFeaturePropertiesResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override diff --git a/java/src/main/java/org/eclipse/ditto/client/management/internal/ThingHandleImpl.java b/java/src/main/java/org/eclipse/ditto/client/management/internal/ThingHandleImpl.java index cddac49c..53085858 100755 --- a/java/src/main/java/org/eclipse/ditto/client/management/internal/ThingHandleImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/management/internal/ThingHandleImpl.java @@ -45,26 +45,17 @@ import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.model.things.ThingsModelFactory; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteAttribute; -import org.eclipse.ditto.signals.commands.things.modify.DeleteAttributeResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteAttributes; -import org.eclipse.ditto.signals.commands.things.modify.DeleteAttributesResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeature; -import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatureResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatures; -import org.eclipse.ditto.signals.commands.things.modify.DeleteFeaturesResponse; import org.eclipse.ditto.signals.commands.things.modify.DeleteThing; -import org.eclipse.ditto.signals.commands.things.modify.DeleteThingResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyAttribute; -import org.eclipse.ditto.signals.commands.things.modify.ModifyAttributeResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyAttributes; -import org.eclipse.ditto.signals.commands.things.modify.ModifyAttributesResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyFeature; -import org.eclipse.ditto.signals.commands.things.modify.ModifyFeatureResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyFeatures; -import org.eclipse.ditto.signals.commands.things.modify.ModifyFeaturesResponse; import org.eclipse.ditto.signals.commands.things.modify.ModifyPolicyId; -import org.eclipse.ditto.signals.commands.things.modify.ModifyPolicyIdResponse; import org.eclipse.ditto.signals.commands.things.query.RetrieveThing; import org.eclipse.ditto.signals.commands.things.query.RetrieveThingResponse; import org.slf4j.Logger; @@ -152,7 +143,7 @@ public F forFeature(final String featureId) { @Override public CompletableFuture delete(final Option[] options) { final DeleteThing command = outgoingMessageFactory.deleteThing(thingId, options); - return askThingCommand(command, DeleteThingResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -186,7 +177,7 @@ public CompletableFuture putAttribute(final JsonPointer path, final JsonVa "If you want to update the whole attributes object, please use the setAttributes(JsonObject) method."); final ModifyAttribute command = outgoingMessageFactory.setAttribute(thingId, path, value, options); - return askThingCommand(command, ModifyAttributeResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -196,7 +187,7 @@ public CompletableFuture setAttributes(final JsonObject attributes, final () -> "The root attributes entry can only be a JSON" + " object or JSON NULL literal!"); final ModifyAttributes command = outgoingMessageFactory.setAttributes(thingId, attributes, options); - return askThingCommand(command, ModifyAttributesResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -204,7 +195,7 @@ public CompletableFuture setFeatures(final Features features, final Option argumentNotNull(features); final ModifyFeatures command = outgoingMessageFactory.setFeatures(thingId, features, options); - return askThingCommand(command, ModifyFeaturesResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -212,7 +203,7 @@ public CompletableFuture setPolicyId(final PolicyId policyId, final Option argumentNotNull(policyId); final ModifyPolicyId command = outgoingMessageFactory.setPolicyId(thingId, policyId, options); - return askThingCommand(command, ModifyPolicyIdResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -220,7 +211,7 @@ public CompletableFuture putFeature(final Feature feature, final Option argumentNotNull(feature); final ModifyFeature command = outgoingMessageFactory.setFeature(thingId, feature, options); - return askThingCommand(command, ModifyFeatureResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override @@ -228,16 +219,15 @@ public CompletableFuture deleteFeature(final String featureId, final Optio argumentNotNull(featureId); final DeleteFeature command = outgoingMessageFactory.deleteFeature(thingId, featureId, options); - return askThingCommand(command, DeleteFeatureResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override public CompletableFuture deleteFeatures(final Option... options) { final DeleteFeatures command = outgoingMessageFactory.deleteFeatures(thingId, options); - return askThingCommand(command, DeleteFeaturesResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } - @Override public CompletableFuture putAttribute(final JsonPointer path, final String value, final Option... options) { @@ -250,13 +240,13 @@ public CompletableFuture deleteAttribute(final JsonPointer path, final Opt checkArgument(path, p -> !p.isEmpty(), () -> "The root attributes object cannot be deleted!"); final DeleteAttribute command = outgoingMessageFactory.deleteAttribute(thingId, path, options); - return askThingCommand(command, DeleteAttributeResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override public CompletableFuture deleteAttributes(final Option... options) { final DeleteAttributes command = outgoingMessageFactory.deleteAttributes(thingId, options); - return askThingCommand(command, DeleteAttributesResponse.class, this::toVoid).toCompletableFuture(); + return askThingCommand(command, CommandResponse.class, this::toVoid).toCompletableFuture(); } @Override diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientAttributesTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientAttributesTest.java index c05b33d4..3d95d37b 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientAttributesTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientAttributesTest.java @@ -14,22 +14,28 @@ import static org.eclipse.ditto.client.TestConstants.Thing.THING_ID; import static org.eclipse.ditto.client.assertions.ClientAssertions.assertThat; +import static org.eclipse.ditto.model.base.acks.AcknowledgementRequest.parseAcknowledgementRequest; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.assertj.core.api.Assertions; +import org.assertj.core.api.Assumptions; import org.eclipse.ditto.client.internal.AbstractDittoClientThingsTest; import org.eclipse.ditto.client.options.Options; import org.eclipse.ditto.json.JsonFactory; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.messages.Message; import org.eclipse.ditto.model.messages.MessageDirection; import org.eclipse.ditto.model.messages.MessageHeaders; import org.eclipse.ditto.model.messages.MessagesModelFactory; import org.eclipse.ditto.model.things.ThingsModelFactory; +import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.commands.things.ThingErrorResponse; import org.eclipse.ditto.signals.commands.things.exceptions.ThingNotAccessibleException; @@ -239,4 +245,38 @@ public void testChangeAttributeWithEmptyPointerThrowsException() { .forId(THING_ID) .putAttribute(JsonFactory.emptyPointer(), "it should fail"); } + + @Test + public void testEventAcknowledgement() { + // Acknowledgements are not implemented for live signals yet + Assumptions.assumeThat(channel).isEqualTo(TopicPath.Channel.TWIN); + + getManagement().startConsumption(); + getManagement().registerForAttributesChanges("Attributes", change -> + change.handleAcknowledgementRequests(handles -> + handles.forEach(handle -> handle.acknowledge( + HttpStatusCode.forInt(Integer.parseInt(handle.getAcknowledgementLabel().toString())) + .orElse(HttpStatusCode.EXPECTATION_FAILED) + )) + ) + ); + // expect subscription messages + assertThat(expectMsgClass(String.class)).startsWith("START-SEND-"); + + reply(AttributeCreated.of(THING_ID, JsonPointer.of("hello"), JsonValue.of("World"), 5L, + DittoHeaders.newBuilder() + .channel(channel.name()) + .acknowledgementRequest( + parseAcknowledgementRequest("200"), + parseAcknowledgementRequest("403"), + parseAcknowledgementRequest("500") + ) + .build()) + ); + Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) + .isEqualTo(HttpStatusCode.OK); + Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) + .isEqualTo(HttpStatusCode.FORBIDDEN); + Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()).isEqualTo(HttpStatusCode.INTERNAL_SERVER_ERROR); + } } diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java index 07199d58..4f1f564c 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java @@ -14,19 +14,26 @@ import static org.eclipse.ditto.client.TestConstants.Thing.THING_ID; import static org.eclipse.ditto.client.assertions.ClientAssertions.assertThat; +import static org.eclipse.ditto.model.base.acks.AcknowledgementRequest.parseAcknowledgementRequest; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import org.assertj.core.api.Assertions; +import org.assertj.core.api.Assumptions; import org.eclipse.ditto.client.internal.AbstractDittoClientThingsTest; import org.eclipse.ditto.client.options.Options; import org.eclipse.ditto.json.JsonFactory; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; +import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.things.Feature; import org.eclipse.ditto.model.things.FeatureDefinition; import org.eclipse.ditto.model.things.ThingsModelFactory; +import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeature; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatureDefinition; @@ -50,6 +57,7 @@ import org.eclipse.ditto.signals.commands.things.modify.ModifyFeaturesResponse; import org.eclipse.ditto.signals.commands.things.query.RetrieveFeature; import org.eclipse.ditto.signals.commands.things.query.RetrieveFeatureResponse; +import org.eclipse.ditto.signals.events.things.FeaturePropertyModified; import org.junit.Test; /** @@ -177,4 +185,38 @@ public void testDeleteFeatureProperties() { expectMsgClass(DeleteFeatureProperties.class).getDittoHeaders())); } + @Test + public void testEventAcknowledgement() { + // Acknowledgements are not implemented for live signals yet + Assumptions.assumeThat(channel).isEqualTo(TopicPath.Channel.TWIN); + + getManagement().startConsumption(); + getManagement().registerForFeatureChanges("Features", change -> + change.handleAcknowledgementRequests(handles -> + handles.forEach(handle -> handle.acknowledge( + HttpStatusCode.forInt(Integer.parseInt(handle.getAcknowledgementLabel().toString())) + .orElse(HttpStatusCode.EXPECTATION_FAILED) + )) + ) + ); + // expect subscription messages + assertThat(expectMsgClass(String.class)).startsWith("START-SEND-"); + + reply(FeaturePropertyModified.of(THING_ID, FEATURE_ID, JsonPointer.of("hello"), JsonValue.of("World"), 5L, + DittoHeaders.newBuilder() + .channel(channel.name()) + .acknowledgementRequest( + parseAcknowledgementRequest("409"), + parseAcknowledgementRequest("201"), + parseAcknowledgementRequest("403") + ) + .build()) + ); + Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) + .isEqualTo(HttpStatusCode.CONFLICT); + Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()).isEqualTo(HttpStatusCode.CREATED); + Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) + .isEqualTo(HttpStatusCode.FORBIDDEN); + } + } From 7083e1e4493e610491ecf812aae9a96dbf28b8f1 Mon Sep 17 00:00:00 2001 From: Yufei Cai Date: Tue, 21 Apr 2020 10:24:50 +0200 Subject: [PATCH 15/23] Move common acknowledgement handling to AbstractHandle; sort branches by specificity; remove unreachable branch; add a test for feature acknowledgement requests. Signed-off-by: Yufei Cai --- .../ditto/client/internal/AbstractHandle.java | 90 +++++++++++++++++- .../client/internal/CommonManagementImpl.java | 93 +------------------ .../client/DittoClientAttributesTest.java | 3 +- .../ditto/client/DittoClientFeaturesTest.java | 33 ++++++- 4 files changed, 123 insertions(+), 96 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java index 37635566..1e7d55f4 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java @@ -17,20 +17,34 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletionStage; import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; +import javax.annotation.Nonnull; + import org.eclipse.ditto.client.internal.bus.Classification; import org.eclipse.ditto.client.messaging.MessagingProvider; +import org.eclipse.ditto.json.JsonField; +import org.eclipse.ditto.json.JsonObject; +import org.eclipse.ditto.json.JsonPointer; +import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.DittoAcknowledgementLabel; +import org.eclipse.ditto.model.base.common.HttpStatusCode; import org.eclipse.ditto.model.base.headers.DittoHeaderDefinition; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.base.headers.WithDittoHeaders; +import org.eclipse.ditto.model.base.json.JsonSchemaVersion; +import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.protocoladapter.Adaptable; import org.eclipse.ditto.protocoladapter.DittoProtocolAdapter; import org.eclipse.ditto.protocoladapter.HeaderTranslator; import org.eclipse.ditto.protocoladapter.ProtocolAdapter; import org.eclipse.ditto.protocoladapter.ProtocolFactory; import org.eclipse.ditto.protocoladapter.TopicPath; +import org.eclipse.ditto.signals.acks.base.Acknowledgement; import org.eclipse.ditto.signals.acks.base.Acknowledgements; import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.commands.base.CommandResponse; @@ -38,6 +52,7 @@ import org.eclipse.ditto.signals.commands.policies.PolicyCommand; import org.eclipse.ditto.signals.commands.policies.PolicyCommandResponse; import org.eclipse.ditto.signals.commands.things.ThingCommand; +import org.eclipse.ditto.signals.commands.things.modify.ThingModifyCommandResponse; /** * Super class of API handles including common methods for request-response handling. @@ -173,12 +188,12 @@ protected CompletionStage sendSignalAndExpectResponse(final Signal< if (expectedErrorResponseClass.isInstance(response)) { // extracted runtime exception will be wrapped in CompletionException. throw onError.apply(expectedErrorResponseClass.cast(response)); - } else if (expectedResponseClass.isInstance(response)) { - return onSuccess.apply(expectedResponseClass.cast(response)); } else if (response instanceof Acknowledgements) { - final CommandResponse commandResponse = CommonManagementImpl - .extractCommandResponseFromAcknowledgements(signal, (Acknowledgements) response); + final CommandResponse commandResponse = + extractCommandResponseFromAcknowledgements(signal, (Acknowledgements) response); return onSuccess.apply(expectedResponseClass.cast(commandResponse)); + } else if (expectedResponseClass.isInstance(response)) { + return onSuccess.apply(expectedResponseClass.cast(response)); } else { throw new ClassCastException("Expect " + expectedResponseClass.getSimpleName() + ", got: " + response); } @@ -235,6 +250,73 @@ protected static Signal adjustHeadersForLiveSignal(final Signal signal) { return adjustHeadersForLive((Signal) signal); } + static CommandResponse extractCommandResponseFromAcknowledgements(final Signal signal, + final Acknowledgements result) { + final CommandResponse response; + response = result.stream() + .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.PERSISTED)) + .findFirst() + .map(ack -> createThingModifyCommandResponseFromAcknowledgement(signal, ack)) + .orElseThrow(() -> new IllegalStateException("Didn't receive an Acknowledgement for label '" + + DittoAcknowledgementLabel.PERSISTED + "'. Please make sure to always request the '" + + DittoAcknowledgementLabel.PERSISTED + "' Acknowledgement if you need to process the " + + "response in the client.")); + return response; + } + + private static ThingModifyCommandResponse> + createThingModifyCommandResponseFromAcknowledgement( + final Signal signal, + final Acknowledgement ack) { + return new ThingModifyCommandResponse>() { + @Override + public JsonPointer getResourcePath() { + return signal.getResourcePath(); + } + + @Override + public String getType() { + return signal.getType().replace(".commands", ".responses"); + } + + @Nonnull + @Override + public String getManifest() { + return getType(); + } + + @Override + public ThingId getThingEntityId() { + return (ThingId) ack.getEntityId(); + } + + @Override + public DittoHeaders getDittoHeaders() { + return ack.getDittoHeaders(); + } + + @Override + public Optional getEntity(final JsonSchemaVersion schemaVersion) { + return ack.getEntity(schemaVersion); + } + + @Override + public ThingModifyCommandResponse setDittoHeaders(final DittoHeaders dittoHeaders) { + return this; + } + + @Override + public HttpStatusCode getStatusCode() { + return ack.getStatusCode(); + } + + @Override + public JsonObject toJson(final JsonSchemaVersion schemaVersion, final Predicate predicate) { + return JsonObject.empty(); + } + }; + } + private static > T adjustHeadersForLive(final T signal) { return signal.setDittoHeaders( signal.getDittoHeaders() diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java index 4be65268..44c6fa61 100755 --- a/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/CommonManagementImpl.java @@ -28,9 +28,7 @@ import java.util.concurrent.CompletionStage; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Predicate; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.eclipse.ditto.client.changes.Change; @@ -51,15 +49,10 @@ import org.eclipse.ditto.client.options.Option; import org.eclipse.ditto.client.options.OptionName; import org.eclipse.ditto.client.options.internal.OptionsEvaluator; -import org.eclipse.ditto.json.JsonField; import org.eclipse.ditto.json.JsonFieldSelector; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; -import org.eclipse.ditto.model.base.acks.DittoAcknowledgementLabel; -import org.eclipse.ditto.model.base.common.HttpStatusCode; -import org.eclipse.ditto.model.base.headers.DittoHeaders; -import org.eclipse.ditto.model.base.json.JsonSchemaVersion; import org.eclipse.ditto.model.messages.Message; import org.eclipse.ditto.model.messages.MessageDirection; import org.eclipse.ditto.model.messages.MessageHeaders; @@ -71,16 +64,12 @@ import org.eclipse.ditto.model.things.ThingsModelFactory; import org.eclipse.ditto.protocoladapter.Adaptable; import org.eclipse.ditto.protocoladapter.TopicPath; -import org.eclipse.ditto.signals.acks.base.Acknowledgement; -import org.eclipse.ditto.signals.acks.base.Acknowledgements; import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.base.WithOptionalEntity; -import org.eclipse.ditto.signals.commands.base.Command; import org.eclipse.ditto.signals.commands.base.CommandResponse; import org.eclipse.ditto.signals.commands.things.modify.CreateThing; import org.eclipse.ditto.signals.commands.things.modify.DeleteThing; import org.eclipse.ditto.signals.commands.things.modify.ModifyThing; -import org.eclipse.ditto.signals.commands.things.modify.ThingModifyCommandResponse; import org.eclipse.ditto.signals.commands.things.query.RetrieveThings; import org.eclipse.ditto.signals.commands.things.query.RetrieveThingsResponse; import org.slf4j.Logger; @@ -375,7 +364,7 @@ private CompletableFuture processCreate(final Thing thing, @Nullable fina return this.askThingCommand(command, // response could be CreateThingResponse or ModifyThingResponse or Acknowledgements. CommandResponse.class, - response -> transformModifyResponse(command, response)) + this::transformModifyResponse) .toCompletableFuture(); } @@ -443,7 +432,7 @@ private CompletableFuture> processPut(final Thing thing, @Nullab return askThingCommand(command, // response could be CreateThingResponse or ModifyThingResponse or Acknowledgements. CommandResponse.class, - response -> Optional.ofNullable(transformModifyResponse(command, response)) + response -> Optional.ofNullable(transformModifyResponse(response)) ).toCompletableFuture(); } @@ -732,16 +721,7 @@ private CompletableFuture> sendRetrieveThingsMessage(final RetrieveT } @Nullable - private Thing transformModifyResponse(final Command command, final CommandResponse result) { - final CommandResponse response; - // also handle Acknowledgements which are a CommandResponse as well: - if (result instanceof Acknowledgements) { - // from the "twin-persisted" acknowledgement, create the actual CommandResponse and feed it back - response = extractCommandResponseFromAcknowledgements(command, (Acknowledgements) result); - } else { - response = result; - } - + private Thing transformModifyResponse(final CommandResponse response) { if (response instanceof WithOptionalEntity) { return ((WithOptionalEntity) response).getEntity(response.getImplementedSchemaVersion()) .filter(JsonValue::isObject) @@ -753,73 +733,6 @@ private Thing transformModifyResponse(final Command command, final CommandRes } } - static CommandResponse extractCommandResponseFromAcknowledgements(final Signal signal, - final Acknowledgements result) { - final CommandResponse response; - response = result.stream() - .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.PERSISTED)) - .findFirst() - .map(ack -> createThingModifyCommandResponseFromAcknowledgement(signal, ack)) - .orElseThrow(() -> new IllegalStateException("Didn't receive an Acknowledgement for label '" + - DittoAcknowledgementLabel.PERSISTED + "'. Please make sure to always request the '" + - DittoAcknowledgementLabel.PERSISTED + "' Acknowledgement if you need to process the " + - "response in the client.")); - return response; - } - - private static ThingModifyCommandResponse> - createThingModifyCommandResponseFromAcknowledgement( - final Signal signal, - final Acknowledgement ack) { - return new ThingModifyCommandResponse>() { - @Override - public JsonPointer getResourcePath() { - return signal.getResourcePath(); - } - - @Override - public String getType() { - return signal.getType().replace(".commands", ".responses"); - } - - @Nonnull - @Override - public String getManifest() { - return getType(); - } - - @Override - public ThingId getThingEntityId() { - return (ThingId) ack.getEntityId(); - } - - @Override - public DittoHeaders getDittoHeaders() { - return ack.getDittoHeaders(); - } - - @Override - public Optional getEntity(final JsonSchemaVersion schemaVersion) { - return ack.getEntity(schemaVersion); - } - - @Override - public ThingModifyCommandResponse setDittoHeaders(final DittoHeaders dittoHeaders) { - return this; - } - - @Override - public HttpStatusCode getStatusCode() { - return ack.getStatusCode(); - } - - @Override - public JsonObject toJson(final JsonSchemaVersion schemaVersion, final Predicate predicate) { - return JsonObject.empty(); - } - }; - } - @FunctionalInterface protected interface NotifyMessage { diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientAttributesTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientAttributesTest.java index 3d95d37b..6c4bc57b 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientAttributesTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientAttributesTest.java @@ -277,6 +277,7 @@ public void testEventAcknowledgement() { .isEqualTo(HttpStatusCode.OK); Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) .isEqualTo(HttpStatusCode.FORBIDDEN); - Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()).isEqualTo(HttpStatusCode.INTERNAL_SERVER_ERROR); + Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) + .isEqualTo(HttpStatusCode.INTERNAL_SERVER_ERROR); } } diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java index 4f1f564c..74130f11 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java @@ -16,6 +16,7 @@ import static org.eclipse.ditto.client.assertions.ClientAssertions.assertThat; import static org.eclipse.ditto.model.base.acks.AcknowledgementRequest.parseAcknowledgementRequest; +import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -27,6 +28,8 @@ import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; +import org.eclipse.ditto.model.base.acks.AcknowledgementRequest; import org.eclipse.ditto.model.base.common.HttpStatusCode; import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.things.Feature; @@ -34,6 +37,7 @@ import org.eclipse.ditto.model.things.ThingsModelFactory; import org.eclipse.ditto.protocoladapter.TopicPath; import org.eclipse.ditto.signals.acks.base.Acknowledgement; +import org.eclipse.ditto.signals.acks.base.Acknowledgements; import org.eclipse.ditto.signals.base.Signal; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeature; import org.eclipse.ditto.signals.commands.things.modify.DeleteFeatureDefinition; @@ -185,6 +189,32 @@ public void testDeleteFeatureProperties() { expectMsgClass(DeleteFeatureProperties.class).getDittoHeaders())); } + @Test + public void testDeleteFeatureWith2Acknowledgements() { + // skip this test for LIVE - 'twin-persisted' is obligatory + Assumptions.assumeThat(channel).isEqualTo(TopicPath.Channel.TWIN); + + final AcknowledgementLabel label1 = AcknowledgementLabel.of("custom-ack-1"); + final AcknowledgementLabel label2 = AcknowledgementLabel.of("twin-persisted"); + assertEventualCompletion(getManagement().forId(THING_ID).forFeature(FEATURE_ID) + .delete(Options.dittoHeaders(DittoHeaders.newBuilder() + .acknowledgementRequest(AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)) + .build()) + )); + + final DittoHeaders sentDittoHeaders = expectMsgClass(DeleteFeature.class).getDittoHeaders(); + reply(Acknowledgements.of( + Arrays.asList( + Acknowledgement.of(label1, THING_ID, HttpStatusCode.OK, DittoHeaders.empty()), + Acknowledgement.of(label2, THING_ID, HttpStatusCode.ACCEPTED, DittoHeaders.empty()) + ), + sentDittoHeaders + )); + + assertThat(sentDittoHeaders.getAcknowledgementRequests()) + .containsExactly(AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)); + } + @Test public void testEventAcknowledgement() { // Acknowledgements are not implemented for live signals yet @@ -214,7 +244,8 @@ public void testEventAcknowledgement() { ); Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) .isEqualTo(HttpStatusCode.CONFLICT); - Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()).isEqualTo(HttpStatusCode.CREATED); + Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) + .isEqualTo(HttpStatusCode.CREATED); Assertions.assertThat(expectMsgClass(Acknowledgement.class).getStatusCode()) .isEqualTo(HttpStatusCode.FORBIDDEN); } From 8fe8d64adbf0227b13162a9588f198113ebb6781 Mon Sep 17 00:00:00 2001 From: Yufei Cai Date: Tue, 21 Apr 2020 13:22:43 +0200 Subject: [PATCH 16/23] Fail client futures on acknowledgements considered failure according to their status code. Signed-off-by: Yufei Cai --- .../ditto/client/internal/AbstractHandle.java | 29 ++++++---- .../AcknowledgementsFailedException.java | 57 +++++++++++++++++++ .../ditto/client/DittoClientFeaturesTest.java | 39 +++++++++++++ .../ditto/client/DittoClientThingTest.java | 38 +++++++++++++ 4 files changed, 152 insertions(+), 11 deletions(-) create mode 100755 java/src/main/java/org/eclipse/ditto/client/management/AcknowledgementsFailedException.java diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java index 1e7d55f4..596473fc 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java @@ -26,6 +26,7 @@ import javax.annotation.Nonnull; import org.eclipse.ditto.client.internal.bus.Classification; +import org.eclipse.ditto.client.management.AcknowledgementsFailedException; import org.eclipse.ditto.client.messaging.MessagingProvider; import org.eclipse.ditto.json.JsonField; import org.eclipse.ditto.json.JsonObject; @@ -251,17 +252,23 @@ protected static Signal adjustHeadersForLiveSignal(final Signal signal) { } static CommandResponse extractCommandResponseFromAcknowledgements(final Signal signal, - final Acknowledgements result) { - final CommandResponse response; - response = result.stream() - .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.PERSISTED)) - .findFirst() - .map(ack -> createThingModifyCommandResponseFromAcknowledgement(signal, ack)) - .orElseThrow(() -> new IllegalStateException("Didn't receive an Acknowledgement for label '" + - DittoAcknowledgementLabel.PERSISTED + "'. Please make sure to always request the '" + - DittoAcknowledgementLabel.PERSISTED + "' Acknowledgement if you need to process the " + - "response in the client.")); - return response; + final Acknowledgements acknowledgements) { + if (areFailedAcknowledgements(acknowledgements.getStatusCode())) { + throw AcknowledgementsFailedException.of(acknowledgements); + } else { + return acknowledgements.stream() + .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.PERSISTED)) + .findFirst() + .map(ack -> createThingModifyCommandResponseFromAcknowledgement(signal, ack)) + .orElseThrow(() -> new IllegalStateException("Didn't receive an Acknowledgement for label '" + + DittoAcknowledgementLabel.PERSISTED + "'. Please make sure to always request the '" + + DittoAcknowledgementLabel.PERSISTED + "' Acknowledgement if you need to process the " + + "response in the client.")); + } + } + + private static boolean areFailedAcknowledgements(final HttpStatusCode statusCode) { + return statusCode.isClientError() || statusCode.isInternalError(); } private static ThingModifyCommandResponse> diff --git a/java/src/main/java/org/eclipse/ditto/client/management/AcknowledgementsFailedException.java b/java/src/main/java/org/eclipse/ditto/client/management/AcknowledgementsFailedException.java new file mode 100755 index 00000000..0c742f39 --- /dev/null +++ b/java/src/main/java/org/eclipse/ditto/client/management/AcknowledgementsFailedException.java @@ -0,0 +1,57 @@ +/* + * 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 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.ditto.client.management; + +import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull; + +import javax.annotation.concurrent.Immutable; + +import org.eclipse.ditto.signals.acks.base.Acknowledgements; + +/** + * This exception is thrown if the requested acknowledgements failed. + * + * @since 1.1.0 + */ +@Immutable +public class AcknowledgementsFailedException extends RuntimeException { + + private static final String MESSAGE_TEMPLATE = "Requested acknowledgements failed with status code %d."; + + private final Acknowledgements acknowledgements; + + private AcknowledgementsFailedException(final Acknowledgements acknowledgements) { + super(String.format(MESSAGE_TEMPLATE, checkNotNull(acknowledgements, "acknowledgements").getStatusCodeValue())); + this.acknowledgements = acknowledgements; + } + + /** + * Create an {@code AcknowledgementsFailedException}. + * + * @param acknowledgements The failed acknowledgements. + * @return The exception. + */ + public static AcknowledgementsFailedException of(final Acknowledgements acknowledgements) { + return new AcknowledgementsFailedException(acknowledgements); + } + + /** + * Get the failed acknowledgements that caused this exception. + * + * @return the failed acknowledgements. + */ + public Acknowledgements getAcknowledgements() { + return acknowledgements; + } + +} diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java index 74130f11..60de73fe 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java @@ -18,11 +18,13 @@ import java.util.Arrays; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; import org.assertj.core.api.Assertions; import org.assertj.core.api.Assumptions; import org.eclipse.ditto.client.internal.AbstractDittoClientThingsTest; +import org.eclipse.ditto.client.management.AcknowledgementsFailedException; import org.eclipse.ditto.client.options.Options; import org.eclipse.ditto.json.JsonFactory; import org.eclipse.ditto.json.JsonObject; @@ -215,6 +217,43 @@ public void testDeleteFeatureWith2Acknowledgements() { .containsExactly(AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)); } + @Test + public void testDeleteFeaturePropertiesWithFailedAcknowledgements() { + // skip this test for LIVE - 'twin-persisted' is obligatory + Assumptions.assumeThat(channel).isEqualTo(TopicPath.Channel.TWIN); + + final AcknowledgementLabel label1 = AcknowledgementLabel.of("custom-ack-1"); + final AcknowledgementLabel label2 = AcknowledgementLabel.of("twin-persisted"); + final Acknowledgements expectedAcknowledgements = Acknowledgements.of( + Arrays.asList( + Acknowledgement.of(label1, THING_ID, HttpStatusCode.FORBIDDEN, DittoHeaders.empty()), + Acknowledgement.of(label2, THING_ID, HttpStatusCode.ACCEPTED, DittoHeaders.empty()) + ), + DittoHeaders.empty() + ); + assertEventualCompletion(getManagement().forFeature(THING_ID, FEATURE_ID) + .deleteProperties(Options.dittoHeaders(DittoHeaders.newBuilder() + .acknowledgementRequest( + AcknowledgementRequest.of(label1), + AcknowledgementRequest.of(label2)) + .build())) + .exceptionally(error -> { + assertThat(error).isInstanceOf(CompletionException.class) + .hasCauseInstanceOf(AcknowledgementsFailedException.class); + final AcknowledgementsFailedException cause = (AcknowledgementsFailedException) error.getCause(); + Assertions.assertThat(cause.getAcknowledgements().setDittoHeaders(DittoHeaders.empty())) + .isEqualTo(expectedAcknowledgements); + return null; + }) + ); + + final DittoHeaders sentDittoHeaders = expectMsgClass(DeleteFeatureProperties.class).getDittoHeaders(); + reply(expectedAcknowledgements.setDittoHeaders(sentDittoHeaders)); + + assertThat(sentDittoHeaders.getAcknowledgementRequests()) + .containsExactly(AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)); + } + @Test public void testEventAcknowledgement() { // Acknowledgements are not implemented for live signals yet diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java index 3146e1d0..2042ab13 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java @@ -30,6 +30,7 @@ import org.assertj.core.api.Assertions; import org.assertj.core.api.Assumptions; import org.eclipse.ditto.client.internal.AbstractDittoClientThingsTest; +import org.eclipse.ditto.client.management.AcknowledgementsFailedException; import org.eclipse.ditto.client.options.Option; import org.eclipse.ditto.client.options.Options; import org.eclipse.ditto.client.registration.DuplicateRegistrationIdException; @@ -128,6 +129,43 @@ public void testCreateThingWith2Acknowledgements() { .containsExactly(AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)); } + @Test + public void testUpdateThingWithFailedAcknowledgements() { + // skip this test for LIVE - 'twin-persisted' is obligatory + Assumptions.assumeThat(channel).isEqualTo(TopicPath.Channel.TWIN); + + final AcknowledgementLabel label1 = AcknowledgementLabel.of("custom-ack-1"); + final AcknowledgementLabel label2 = AcknowledgementLabel.of("twin-persisted"); + final Acknowledgements expectedAcknowledgements = Acknowledgements.of( + Arrays.asList( + Acknowledgement.of(label1, THING_ID, HttpStatusCode.FORBIDDEN, DittoHeaders.empty()), + Acknowledgement.of(label2, THING_ID, HttpStatusCode.ACCEPTED, DittoHeaders.empty()) + ), + DittoHeaders.empty() + ); + assertEventualCompletion(getManagement() + .update(THING, Options.dittoHeaders(DittoHeaders.newBuilder() + .acknowledgementRequest( + AcknowledgementRequest.of(label1), + AcknowledgementRequest.of(label2)) + .build())) + .exceptionally(error -> { + assertThat(error).isInstanceOf(CompletionException.class) + .hasCauseInstanceOf(AcknowledgementsFailedException.class); + final AcknowledgementsFailedException cause = (AcknowledgementsFailedException) error.getCause(); + assertThat(cause.getAcknowledgements().setDittoHeaders(DittoHeaders.empty())) + .isEqualTo(expectedAcknowledgements); + return null; + }) + ); + + final DittoHeaders sentDittoHeaders = expectMsgClass(ModifyThing.class).getDittoHeaders(); + reply(expectedAcknowledgements.setDittoHeaders(sentDittoHeaders)); + + assertThat(sentDittoHeaders.getAcknowledgementRequests()) + .containsExactly(AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)); + } + @Test public void createThingFailsWithExistsOption() { assertThatExceptionOfType(IllegalArgumentException.class) From 87bdac6dd58e39501fe88ccb827d1fc8e5b88334 Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Tue, 21 Apr 2020 19:47:59 +0200 Subject: [PATCH 17/23] Issue eclipse/ditto#611: review: added serialVersionUID to RuntimeException Signed-off-by: Thomas Jaeckle --- .../client/management/AcknowledgementsFailedException.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/management/AcknowledgementsFailedException.java b/java/src/main/java/org/eclipse/ditto/client/management/AcknowledgementsFailedException.java index 0c742f39..1d1e12af 100755 --- a/java/src/main/java/org/eclipse/ditto/client/management/AcknowledgementsFailedException.java +++ b/java/src/main/java/org/eclipse/ditto/client/management/AcknowledgementsFailedException.java @@ -19,13 +19,15 @@ import org.eclipse.ditto.signals.acks.base.Acknowledgements; /** - * This exception is thrown if the requested acknowledgements failed. + * This exception is thrown in the Ditto client if the requested acknowledgements failed. * * @since 1.1.0 */ @Immutable public class AcknowledgementsFailedException extends RuntimeException { + private static final long serialVersionUID = -4578923424099138760L; + private static final String MESSAGE_TEMPLATE = "Requested acknowledgements failed with status code %d."; private final Acknowledgements acknowledgements; From 74fd6f1dd4b42773976a335703940b41919d51f9 Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Wed, 22 Apr 2020 12:44:13 +0200 Subject: [PATCH 18/23] Issue eclipse/ditto#611: renamed Options.dittoHeaders() to Options.headers() Signed-off-by: Thomas Jaeckle --- .../ditto/client/internal/AbstractHandle.java | 6 +- .../eclipse/ditto/client/options/Options.java | 2 +- .../ditto/client/DittoClientFeaturesTest.java | 4 +- .../ditto/client/DittoClientThingTest.java | 4 +- .../client/DittoClientUsageExamples.java | 227 +++++++++++------- .../internal/GlobalOptionsEvaluatorTest.java | 2 +- 6 files changed, 147 insertions(+), 98 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java index 596473fc..14c07439 100644 --- a/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java +++ b/java/src/main/java/org/eclipse/ditto/client/internal/AbstractHandle.java @@ -257,12 +257,12 @@ static CommandResponse extractCommandResponseFromAcknowledgements(final Signa throw AcknowledgementsFailedException.of(acknowledgements); } else { return acknowledgements.stream() - .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.PERSISTED)) + .filter(ack -> ack.getLabel().equals(DittoAcknowledgementLabel.TWIN_PERSISTED)) .findFirst() .map(ack -> createThingModifyCommandResponseFromAcknowledgement(signal, ack)) .orElseThrow(() -> new IllegalStateException("Didn't receive an Acknowledgement for label '" + - DittoAcknowledgementLabel.PERSISTED + "'. Please make sure to always request the '" + - DittoAcknowledgementLabel.PERSISTED + "' Acknowledgement if you need to process the " + + DittoAcknowledgementLabel.TWIN_PERSISTED + "'. Please make sure to always request the '" + + DittoAcknowledgementLabel.TWIN_PERSISTED + "' Acknowledgement if you need to process the " + "response in the client.")); } } diff --git a/java/src/main/java/org/eclipse/ditto/client/options/Options.java b/java/src/main/java/org/eclipse/ditto/client/options/Options.java index 4db14bc5..f558e264 100755 --- a/java/src/main/java/org/eclipse/ditto/client/options/Options.java +++ b/java/src/main/java/org/eclipse/ditto/client/options/Options.java @@ -42,7 +42,7 @@ private Options() { * @return the new option. * @since 1.1.0 */ - public static Option dittoHeaders(final DittoHeaders dittoHeaders) { + public static Option headers(final DittoHeaders dittoHeaders) { return DefaultOption.newInstance(OptionName.Global.DITTO_HEADERS, dittoHeaders); } diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java index 60de73fe..f3612ac4 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientFeaturesTest.java @@ -199,7 +199,7 @@ public void testDeleteFeatureWith2Acknowledgements() { final AcknowledgementLabel label1 = AcknowledgementLabel.of("custom-ack-1"); final AcknowledgementLabel label2 = AcknowledgementLabel.of("twin-persisted"); assertEventualCompletion(getManagement().forId(THING_ID).forFeature(FEATURE_ID) - .delete(Options.dittoHeaders(DittoHeaders.newBuilder() + .delete(Options.headers(DittoHeaders.newBuilder() .acknowledgementRequest(AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)) .build()) )); @@ -232,7 +232,7 @@ public void testDeleteFeaturePropertiesWithFailedAcknowledgements() { DittoHeaders.empty() ); assertEventualCompletion(getManagement().forFeature(THING_ID, FEATURE_ID) - .deleteProperties(Options.dittoHeaders(DittoHeaders.newBuilder() + .deleteProperties(Options.headers(DittoHeaders.newBuilder() .acknowledgementRequest( AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)) diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java index 2042ab13..3d1584c8 100644 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientThingTest.java @@ -109,7 +109,7 @@ public void testCreateThingWith2Acknowledgements() { final AcknowledgementLabel label1 = AcknowledgementLabel.of("custom-ack-1"); final AcknowledgementLabel label2 = AcknowledgementLabel.of("twin-persisted"); assertEventualCompletion(getManagement() - .create(THING_ID, Options.dittoHeaders(DittoHeaders.newBuilder() + .create(THING_ID, Options.headers(DittoHeaders.newBuilder() .acknowledgementRequest( AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)) @@ -144,7 +144,7 @@ public void testUpdateThingWithFailedAcknowledgements() { DittoHeaders.empty() ); assertEventualCompletion(getManagement() - .update(THING, Options.dittoHeaders(DittoHeaders.newBuilder() + .update(THING, Options.headers(DittoHeaders.newBuilder() .acknowledgementRequest( AcknowledgementRequest.of(label1), AcknowledgementRequest.of(label2)) diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientUsageExamples.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientUsageExamples.java index 4eff44e6..6c6bbc5e 100755 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientUsageExamples.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientUsageExamples.java @@ -50,6 +50,7 @@ import org.eclipse.ditto.json.JsonFieldSelector; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; import org.eclipse.ditto.model.base.common.HttpStatusCode; import org.eclipse.ditto.model.base.exceptions.DittoRuntimeException; import org.eclipse.ditto.model.base.json.JsonSchemaVersion; @@ -61,8 +62,6 @@ import org.eclipse.ditto.model.things.ThingBuilder; import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.model.things.ThingsModelFactory; -import org.eclipse.ditto.protocoladapter.JsonifiableAdaptable; -import org.eclipse.ditto.protocoladapter.ProtocolFactory; import org.eclipse.ditto.signals.commands.live.modify.CreateThingLiveCommandAnswerBuilder; import org.eclipse.ditto.signals.commands.live.modify.ModifyFeaturePropertyLiveCommandAnswerBuilder; import org.slf4j.Logger; @@ -78,7 +77,8 @@ public final class DittoClientUsageExamples { private static final Logger LOGGER = LoggerFactory.getLogger(DittoClientUsageExamples.class); - private static final String PROPERTIES_FILE = "ditto-client-starter-local.properties"; // for local development + private static final String PROPERTIES_FILE = "ditto-client-starter-aws-dev.properties"; +// private static final String PROPERTIES_FILE = "ditto-client-starter-local.properties"; // for local development // private static final String PROPERTIES_FILE = "ditto-client-starter-sandbox.properties"; private static final String PROXY_HOST; private static final String PROXY_PORT; @@ -98,105 +98,154 @@ public final class DittoClientUsageExamples { public static void main(final String... args) throws ExecutionException, InterruptedException { final DittoClient client = DittoClients.newInstance(createMessagingProvider()); - final DittoClient client2 = DittoClients.newInstance(createMessagingProvider()); +// final DittoClient client2 = DittoClients.newInstance(createMessagingProvider()); if (shouldNotSkip("twin.examples")) { - final JsonifiableAdaptable jsonifiableAdaptable = ProtocolFactory.jsonifiableAdaptableFromJson( - JsonFactory.readFrom("{\n" + - " \"topic\": \"org.eclipse.ditto/xdk_53/things/twin/commands/modify\",\n" + - " \"headers\": {},\n" + - " \"path\": \"/\",\n" + - " \"value\": {\n" + - " \"thingId\": \"org.eclipse.ditto:xdk_53\",\n" + - " \"attributes\": {\n" + - " \"location\": {\n" + - " \"latitude\": 44.673856,\n" + - " \"longitude\": 8.261719\n" + - " }\n" + - " },\n" + - " \"features\": {\n" + - " \"accelerometer\": {\n" + - " \"properties\": {\n" + - " \"x\": 3.141,\n" + - " \"y\": 2.718,\n" + - " \"z\": 1,\n" + - " \"unit\": \"g\"\n" + - " }\n" + - " }\n" + - " }\n" + - " }\n" + - "}").asObject()); - client.sendDittoProtocol(jsonifiableAdaptable).whenComplete((a, t) -> { - if (a != null) { - LOGGER.info("sendDittoProtocol: Received adaptable as response: {}", a); - } - if (t != null) { - LOGGER.warn("sendDittoProtocol: Received throwable as response", t); - } - }); +// final JsonifiableAdaptable jsonifiableAdaptable = ProtocolFactory.jsonifiableAdaptableFromJson( +// JsonFactory.readFrom("{\n" + +// " \"topic\": \"org.eclipse.ditto/xdk_53/things/twin/commands/modify\",\n" + +// " \"headers\": {},\n" + +// " \"path\": \"/\",\n" + +// " \"value\": {\n" + +// " \"thingId\": \"org.eclipse.ditto:xdk_53\",\n" + +// " \"attributes\": {\n" + +// " \"location\": {\n" + +// " \"latitude\": 44.673856,\n" + +// " \"longitude\": 8.261719\n" + +// " }\n" + +// " },\n" + +// " \"features\": {\n" + +// " \"accelerometer\": {\n" + +// " \"properties\": {\n" + +// " \"x\": 3.141,\n" + +// " \"y\": 2.718,\n" + +// " \"z\": 1,\n" + +// " \"unit\": \"g\"\n" + +// " }\n" + +// " }\n" + +// " }\n" + +// " }\n" + +// "}").asObject()); +// client.sendDittoProtocol(jsonifiableAdaptable).whenComplete((a, t) -> { +// if (a != null) { +// LOGGER.info("sendDittoProtocol: Received adaptable as response: {}", a); +// } +// if (t != null) { +// LOGGER.warn("sendDittoProtocol: Received throwable as response", t); +// } +// }); client.twin().startConsumption().get(); - client2.twin().startConsumption().get(); +// client2.twin().startConsumption().get(); LOGGER.info("Subscribed for Twin events"); client.live().startConsumption().get(); - client2.live().startConsumption().get(); +// client2.live().startConsumption().get(); LOGGER.info("Subscribed for Live events/commands/messages"); - System.out.println("\n\nContinuing with TWIN commands/events demo:"); - useTwinCommandsAndEvents(client, client2); - System.out.println("\n\nFinished with TWIN commands/events demo"); - } - - if (shouldNotSkip("live.examples")) { - client.live().startConsumption().get(); - client2.live().startConsumption().get(); - - System.out.println("\n\nAbout to continue with LIVE commands/events demo:"); - promptEnterKey(); - - useLiveCommands(client, client2); - System.out.println("\n\nFinished with LIVE commands/events demo"); - - System.out.println("\n\nAbout to continue with LIVE messages demo:"); - promptEnterKey(); - - useLiveMessages(client, client2); - System.out.println("\n\nFinished with LIVE messages demo"); - Thread.sleep(500); - } - - if (shouldNotSkip("search.examples")) { - System.out.println("\n\nAbout to continue with search commands:"); - promptEnterKey(); - useSearchCommands(client); - System.out.println("\n\nFinished with SEARCH commands demo"); - Thread.sleep(500); - } + client.twin().registerForThingChanges("th", change -> { + LOGGER.info("Got thing change: {}", change); + change.handleAcknowledgementRequest(AcknowledgementLabel.of("my-custom-ack"), handle -> + handle.acknowledge(HttpStatusCode.OK, JsonObject.newBuilder() + .set("outcome", JsonValue.of("thing")) + .build() + ) + ); + change.handleAcknowledgementRequest(AcknowledgementLabel.of("websocket"), handle -> + handle.acknowledge(HttpStatusCode.OK, JsonObject.newBuilder() + .set("outcome", JsonValue.of("I am WebSocket!")) + .build() + ) + ); + }); - if (shouldNotSkip("load.test")) { - System.out.println("\n\nAbout to continue with small load test:"); - promptEnterKey(); + client.twin().registerForFeatureChanges("fo", change -> { + LOGGER.info("Got feature change: {}", change); + change.handleAcknowledgementRequest(AcknowledgementLabel.of("my-custom-feature"), handle -> + handle.acknowledge(HttpStatusCode.OK, JsonObject.newBuilder() + .set("outcome", JsonValue.of("feature")) + .build() + ) + ); + }); - final int loadTestThings = 100; - final int loadTestCount = 10; - subscribeForLoadTestUpdateChanges(client2, loadTestCount * loadTestThings, false); - performLoadTestUpdate(client, loadTestCount, loadTestThings, false); - performLoadTestRead(client, loadTestCount, true); - Thread.sleep(1000); - } + client.twin().registerForAttributesChanges("at", change -> { + LOGGER.info("Got attribute change: {}", change); + change.handleAcknowledgementRequest(AcknowledgementLabel.of("my-custom-attribute"), handle -> + handle.acknowledge(HttpStatusCode.CREATED, JsonObject.newBuilder() + .set("outcome", JsonValue.of("attribute")) + .build() + ) + ); + }); - if (shouldNotSkip("policies.examples")) { - System.out.println("\n\nAbout to continue with policy example:"); - promptEnterKey(); - addNewSubjectToExistingPolicy(client); - System.out.println("\n\nFinished with policy example"); +// final ThingId thingId = ThingId.inDefaultNamespace(UUID.randomUUID().toString()); +// client2.twin().create(thingId).get(); +// client2.twin().forId(thingId).putAttribute("test", 42, Options.dittoHeaders( +// DittoHeaders.newBuilder() +// .acknowledgementRequest(AcknowledgementRequest.of(DittoAcknowledgementLabel.PERSISTED), +// AcknowledgementRequest.of(AcknowledgementLabel.of("my-custom-attribute")) +// ) +// .build() +// )).whenComplete((v, t) -> { +// System.out.println("V: " + v); +// System.out.println("t: " + t); +// }); + +// System.out.println("\n\nContinuing with TWIN commands/events demo:"); +// useTwinCommandsAndEvents(client, client2); +// System.out.println("\n\nFinished with TWIN commands/events demo"); } - client.destroy(); - client2.destroy(); - System.out.println("\n\nDittoClientUsageExamples successfully completed!"); - System.exit(0); +// if (shouldNotSkip("live.examples")) { +// client.live().startConsumption().get(); +// client2.live().startConsumption().get(); +// +// System.out.println("\n\nAbout to continue with LIVE commands/events demo:"); +// promptEnterKey(); +// +// useLiveCommands(client, client2); +// System.out.println("\n\nFinished with LIVE commands/events demo"); +// +// System.out.println("\n\nAbout to continue with LIVE messages demo:"); +// promptEnterKey(); +// +// useLiveMessages(client, client2); +// System.out.println("\n\nFinished with LIVE messages demo"); +// Thread.sleep(500); +// } +// +// if (shouldNotSkip("search.examples")) { +// System.out.println("\n\nAbout to continue with search commands:"); +// promptEnterKey(); +// useSearchCommands(client); +// System.out.println("\n\nFinished with SEARCH commands demo"); +// Thread.sleep(500); +// } +// +// if (shouldNotSkip("load.test")) { +// System.out.println("\n\nAbout to continue with small load test:"); +// promptEnterKey(); +// +// final int loadTestThings = 100; +// final int loadTestCount = 10; +// subscribeForLoadTestUpdateChanges(client2, loadTestCount * loadTestThings, false); +// performLoadTestUpdate(client, loadTestCount, loadTestThings, false); +// performLoadTestRead(client, loadTestCount, true); +// Thread.sleep(1000); +// } +// +// if (shouldNotSkip("policies.examples")) { +// System.out.println("\n\nAbout to continue with policy example:"); +// promptEnterKey(); +// addNewSubjectToExistingPolicy(client); +// System.out.println("\n\nFinished with policy example"); +// } + +// client.destroy(); +// client2.destroy(); +// System.out.println("\n\nDittoClientUsageExamples successfully completed!"); +// System.exit(0); } private static void addNewSubjectToExistingPolicy(final DittoClient client) @@ -721,7 +770,7 @@ private static MessagingProvider createMessagingProvider() { AuthenticationProviders.dummy(DummyAuthenticationConfiguration.newBuilder() .dummyUsername(DITTO_DUMMY_AUTH_USER) .build()); - } else if (DITTO_OAUTH_CLIENT_ID != null) { + } else if (DITTO_OAUTH_CLIENT_ID != null && !DITTO_OAUTH_CLIENT_ID.isEmpty()) { final ClientCredentialsAuthenticationConfiguration.ClientCredentialsAuthenticationConfigurationBuilder authenticationConfigurationBuilder = ClientCredentialsAuthenticationConfiguration.newBuilder() diff --git a/java/src/test/java/org/eclipse/ditto/client/options/internal/GlobalOptionsEvaluatorTest.java b/java/src/test/java/org/eclipse/ditto/client/options/internal/GlobalOptionsEvaluatorTest.java index dbb78e21..0fb7cee1 100644 --- a/java/src/test/java/org/eclipse/ditto/client/options/internal/GlobalOptionsEvaluatorTest.java +++ b/java/src/test/java/org/eclipse/ditto/client/options/internal/GlobalOptionsEvaluatorTest.java @@ -37,7 +37,7 @@ public final class GlobalOptionsEvaluatorTest { private static final DittoHeaders KNOWN_DITTO_HEADERS = DittoHeaders.newBuilder() .correlationId(UUID.randomUUID().toString()) .build(); - private static final Option DITTO_HEADERS_OPTION = Options.dittoHeaders(KNOWN_DITTO_HEADERS); + private static final Option DITTO_HEADERS_OPTION = Options.headers(KNOWN_DITTO_HEADERS); private OptionsEvaluator.Global underTest = null; From 5ec9cc646ba30c7c91a6e44823a66257f5bafef3 Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Thu, 23 Apr 2020 08:24:59 +0200 Subject: [PATCH 19/23] updated Ditto Java Client legal documents Signed-off-by: Thomas Jaeckle --- legal/3rd-party-dependencies/compile.txt | 9 +- legal/3rd-party-dependencies/cqs.md | 55 +++++--- legal/3rd-party-dependencies/generateCqsMd.sh | 6 + legal/3rd-party-dependencies/listDeps.sh | 13 +- .../3rd-party-dependencies/listMvnPlugins.sh | 4 +- .../3rd-party-dependencies/maven-plugins.txt | 33 ++--- legal/3rd-party-dependencies/provided.txt | 2 +- legal/3rd-party-dependencies/runtime.txt | 0 legal/3rd-party-dependencies/test.txt | 88 +++++++------ legal/NOTICE-THIRD-PARTY.md | 16 ++- legal/licenses/CC0.txt | 121 ++++++++++++++++++ 11 files changed, 257 insertions(+), 90 deletions(-) create mode 100644 legal/3rd-party-dependencies/runtime.txt create mode 100644 legal/licenses/CC0.txt diff --git a/legal/3rd-party-dependencies/compile.txt b/legal/3rd-party-dependencies/compile.txt index fcd2167d..cd2f5b6b 100644 --- a/legal/3rd-party-dependencies/compile.txt +++ b/legal/3rd-party-dependencies/compile.txt @@ -1,4 +1,5 @@ - com.eclipsesource.minimal-json:minimal-json:jar:0.9.5:compile - com.neovisionaries:nv-websocket-client:jar:2.9:compile - org.atteo.classindex:classindex:jar:3.7:compile - org.slf4j:slf4j-api:jar:1.7.25:compile +com.eclipsesource.minimal-json:minimal-json:jar:0.9.5:compile +com.neovisionaries:nv-websocket-client:jar:2.9:compile +org.atteo.classindex:classindex:jar:3.8:compile +org.reactivestreams:reactive-streams:jar:1.0.3:compile +org.slf4j:slf4j-api:jar:1.7.28:compile diff --git a/legal/3rd-party-dependencies/cqs.md b/legal/3rd-party-dependencies/cqs.md index 73c44788..40730cd2 100644 --- a/legal/3rd-party-dependencies/cqs.md +++ b/legal/3rd-party-dependencies/cqs.md @@ -6,8 +6,14 @@ |---|---|---|---| |com.eclipsesource.minimal-json|minimal-json|0.9.5| [16296](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=16296) | |com.neovisionaries|nv-websocket-client|2.9| [20409](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=20409) | -|org.atteo.classindex|classindex|3.7| [18906](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=18906) TODO: update | -|org.slf4j|slf4j-api|1.7.25| [14404](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=14404) | +|org.atteo.classindex|classindex|3.8| [20713](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=20713) | +|org.reactivestreams|reactive-streams|1.0.3| [16332](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=16332) | +|org.slf4j|slf4j-api|1.7.28| [14404](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=14404) | + +## Eclipse CQs - Runtime + +| Group ID | Artifact ID | Version | CQ | +|---|---|---|---| ## Works-With dependencies @@ -17,19 +23,22 @@ |biz.aQute.bnd|bndlib|2.4.0| []() | |ch.qos.logback|logback-classic|1.2.3| []() | |ch.qos.logback|logback-core|1.2.3| []() | +|com.beust|jcommander|1.72| []() | |junit|junit|4.12| []() | -|net.bytebuddy|byte-buddy-agent|1.7.0| []() | -|net.bytebuddy|byte-buddy|1.7.0| []() | +|net.bytebuddy|byte-buddy-agent|1.9.10| []() | +|net.bytebuddy|byte-buddy|1.9.10| []() | |net.javacrumbs.json-unit|json-unit-core|1.28.1| []() | |net.javacrumbs.json-unit|json-unit|1.28.1| []() | |nl.jqno.equalsverifier|equalsverifier|3.0.3| []() | -|org.apache.felix|org.apache.felix.framework|5.4.0| []() | +|org.apache-extras.beanshell|bsh|2.0b6| []() | +|org.apache.felix|org.apache.felix.framework|6.0.3| []() | |org.apache.servicemix.bundles|org.apache.servicemix.bundles.javax-inject|1_2| []() | -|org.assertj|assertj-core|3.11.1| []() | +|org.assertj|assertj-core|3.12.0| []() | +|org.codehaus.mojo|animal-sniffer-annotations|1.9| []() | |org.hamcrest|hamcrest-core|1.3| []() | |org.json|json|20090211| []() | -|org.mockito|mockito-core|2.9.0| []() | -|org.mutabilitydetector|MutabilityDetector|0.9.6| []() | +|org.mockito|mockito-core|3.1.0| []() | +|org.mutabilitydetector|MutabilityDetector|0.10.2| []() | |org.objenesis|objenesis|2.6| []() | |org.ops4j.base|ops4j-base-io|1.5.0| []() | |org.ops4j.base|ops4j-base-lang|1.5.0| []() | @@ -38,35 +47,41 @@ |org.ops4j.base|ops4j-base-spi|1.5.0| []() | |org.ops4j.base|ops4j-base-store|1.5.0| []() | |org.ops4j.base|ops4j-base-util-property|1.5.0| []() | -|org.ops4j.pax.exam|pax-exam-container-native|4.8.0| []() | -|org.ops4j.pax.exam|pax-exam|4.8.0| []() | -|org.ops4j.pax.exam|pax-exam-junit4|4.8.0| []() | -|org.ops4j.pax.exam|pax-exam-link-mvn|4.8.0| []() | -|org.ops4j.pax.exam|pax-exam-spi|4.8.0| []() | +|org.ops4j.pax.exam|pax-exam-container-native|4.13.0| []() | +|org.ops4j.pax.exam|pax-exam|4.13.0| []() | +|org.ops4j.pax.exam|pax-exam-junit4|4.13.0| []() | +|org.ops4j.pax.exam|pax-exam-link-mvn|4.13.0| []() | +|org.ops4j.pax.exam|pax-exam-spi|4.13.0| []() | |org.ops4j.pax.swissbox|pax-swissbox-core|1.8.2| []() | |org.ops4j.pax.swissbox|pax-swissbox-lifecycle|1.8.2| []() | |org.ops4j.pax.swissbox|pax-swissbox-optional-jcl|1.8.2| []() | |org.ops4j.pax.swissbox|pax-swissbox-property|1.8.2| []() | |org.ops4j.pax.swissbox|pax-swissbox-tracker|1.8.2| []() | |org.ops4j.pax.tinybundles|tinybundles|2.1.1| []() | -|org.ops4j.pax.url|pax-url-aether|2.4.2| []() | -|org.ops4j.pax.url|pax-url-classpath|2.4.2| []() | -|org.ops4j.pax.url|pax-url-commons|2.4.2| []() | -|org.ops4j.pax.url|pax-url-link|2.4.2| []() | +|org.ops4j.pax.url|pax-url-aether|2.4.5| []() | +|org.ops4j.pax.url|pax-url-classpath|2.4.5| []() | +|org.ops4j.pax.url|pax-url-commons|2.4.5| []() | +|org.ops4j.pax.url|pax-url-link|2.4.5| []() | +|org.reactivestreams|reactive-streams-examples|1.0.3| []() | +|org.reactivestreams|reactive-streams-tck|1.0.3| []() | |org.skyscreamer|jsonassert|1.2.3| []() | |org.slf4j|jcl-over-slf4j|1.6.6| []() | -|com.github.siom79.japicmp|japicmp-maven-plugin|0.11.0| []() | +|org.testng|test| []() | +|com.github.siom79.japicmp|japicmp-maven-plugin|0.14.3| []() | |com.mycila|license-maven-plugin|3.0| []() | |org.apache.felix|maven-bundle-plugin|3.5.0| []() | |org.apache.maven.plugins|maven-assembly-plugin|3.1.0| []() | |org.apache.maven.plugins|maven-clean-plugin|2.5| []() | |org.apache.maven.plugins|maven-compiler-plugin|3.7.0| []() | +|org.apache.maven.plugins|maven-dependency-plugin|3.0.2| []() | |org.apache.maven.plugins|maven-deploy-plugin|2.8.2| []() | -|org.apache.maven.plugins|maven-failsafe-plugin|3.0.0-M1| []() | +|org.apache.maven.plugins|maven-failsafe-plugin|3.0.0-M4| []() | |org.apache.maven.plugins|maven-install-plugin|2.5.2| []() | |org.apache.maven.plugins|maven-resources-plugin|3.0.2| []() | |org.apache.maven.plugins|maven-scm-plugin|1.9.5| []() | |org.apache.maven.plugins|maven-site-plugin|3.3| []() | -|org.apache.maven.plugins|maven-surefire-plugin|3.0.0-M1| []() | +|org.apache.maven.plugins|maven-surefire-plugin|3.0.0-M4| []() | +|org.codehaus.mojo|flatten-maven-plugin|1.0.1| []() | |org.codehaus.mojo|license-maven-plugin|1.17| []() | |org.codehaus.mojo|versions-maven-plugin|2.5| []() | +|org.jacoco|jacoco-maven-plugin|0.8.5| []() | diff --git a/legal/3rd-party-dependencies/generateCqsMd.sh b/legal/3rd-party-dependencies/generateCqsMd.sh index f87e4946..39765ee7 100755 --- a/legal/3rd-party-dependencies/generateCqsMd.sh +++ b/legal/3rd-party-dependencies/generateCqsMd.sh @@ -17,6 +17,12 @@ echo "| Group ID | Artifact ID | Version | CQ |" echo "|---|---|---|---|" cat compile.txt|cut -d':' -f1,2,4|sed -e 's/:/|/g'|while read i; do echo "|$i| []() |";done echo "" +echo "## Eclipse CQs - Runtime" +echo "" +echo "| Group ID | Artifact ID | Version | CQ |" +echo "|---|---|---|---|" +cat runtime.txt|cut -d':' -f1,2,4|sed -e 's/:/|/g'|while read i; do echo "|$i| []() |";done +echo "" echo "## Works-With dependencies" echo "" echo "| Group ID | Artifact ID | Version | CQ |" diff --git a/legal/3rd-party-dependencies/listDeps.sh b/legal/3rd-party-dependencies/listDeps.sh index 9a85026a..2ff51a04 100755 --- a/legal/3rd-party-dependencies/listDeps.sh +++ b/legal/3rd-party-dependencies/listDeps.sh @@ -11,13 +11,20 @@ # SPDX-License-Identifier: EPL-2.0 cd ../../java/ mvn dependency:list -DexcludeGroupIds=org.eclipse.ditto,rubygems -Dsort=true -DoutputFile=dependencies.txt -find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:compile'|sort|uniq > ../legal/3rd-party-dependencies//compile.txt -find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:test'|sort|uniq > ../legal/3rd-party-dependencies//test.txt -find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:provided'|sort|uniq > ../legal/3rd-party-dependencies//provided.txt +find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:compile'| tr -d '[:blank:]'| sed -e 's/(optional)//' -e 's/:compile.*/:compile/'|sort|uniq > ../legal/3rd-party-dependencies//compile.txt +find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:runtime'| tr -d '[:blank:]'| sed -e 's/(optional)//' -e 's/:runtime.*/:runtime/'|sort|uniq > ../legal/3rd-party-dependencies//runtime.txt +find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:test'| tr -d '[:blank:]'| sed -e 's/(optional)//' -e 's/:test.*/:test/'|sort|uniq > ../legal/3rd-party-dependencies//test.txt +find . -name dependencies.txt|while read i; do cat $i;done|grep '.*:.*:provided'| tr -d '[:blank:]'| sed -e 's/(optional)//' -e 's/:provided.*/:provided/'|sort|uniq > ../legal/3rd-party-dependencies//provided.txt + +# Cleanup temp files find . -name dependencies.txt|while read i; do rm $i;done + cd ../legal/3rd-party-dependencies/ + +# exclude compile dependencies from provided.txt + sort + remove duplicates cat compile.txt|cut -d':' -f1-4|while read i; do grep -h $i provided.txt;done|sort|uniq|while read x; do sed -i.bak -e s/$x// provided.txt ;done sed -i.bak '/^[[:space:]]*$/d' provided.txt +# exclude compile+provided dependencies from test.txt + sort + remove duplicates cat compile.txt provided.txt|cut -d':' -f1-4|while read i; do grep -h $i test.txt;done|sort|uniq|while read x; do sed -i.bak -e s/$x// test.txt ;done sed -i.bak '/^[[:space:]]*$/d' test.txt rm *.bak diff --git a/legal/3rd-party-dependencies/listMvnPlugins.sh b/legal/3rd-party-dependencies/listMvnPlugins.sh index 2ccfe267..11263537 100755 --- a/legal/3rd-party-dependencies/listMvnPlugins.sh +++ b/legal/3rd-party-dependencies/listMvnPlugins.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2019 Contributors to the Eclipse Foundation +# Copyright (c) 2017 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -11,7 +11,7 @@ # SPDX-License-Identifier: EPL-2.0 cd ../../java/ mvn dependency:list dependency:resolve-plugins -DoutputFile=plugins.txt -find . -name plugins.txt|while read i; do cat $i;done|grep '.*:.*:runtime$'|sort|uniq > ../legal/3rd-party-dependencies/maven-plugins.txt +find . -name plugins.txt|while read i; do cat $i;done|grep '.*:.*:runtime$'| tr -d '[:blank:]'|sort|uniq > ../legal/3rd-party-dependencies/maven-plugins.txt find . -name plugins.txt|while read i; do rm $i;done cd ../legal/3rd-party-dependencies/ diff --git a/legal/3rd-party-dependencies/maven-plugins.txt b/legal/3rd-party-dependencies/maven-plugins.txt index a4798c5b..b672947c 100644 --- a/legal/3rd-party-dependencies/maven-plugins.txt +++ b/legal/3rd-party-dependencies/maven-plugins.txt @@ -1,15 +1,18 @@ - com.github.siom79.japicmp:japicmp-maven-plugin:maven-plugin:0.11.0:runtime - com.mycila:license-maven-plugin:maven-plugin:3.0:runtime - org.apache.felix:maven-bundle-plugin:maven-plugin:3.5.0:runtime - org.apache.maven.plugins:maven-assembly-plugin:maven-plugin:3.1.0:runtime - org.apache.maven.plugins:maven-clean-plugin:maven-plugin:2.5:runtime - org.apache.maven.plugins:maven-compiler-plugin:maven-plugin:3.7.0:runtime - org.apache.maven.plugins:maven-deploy-plugin:maven-plugin:2.8.2:runtime - org.apache.maven.plugins:maven-failsafe-plugin:maven-plugin:3.0.0-M1:runtime - org.apache.maven.plugins:maven-install-plugin:maven-plugin:2.5.2:runtime - org.apache.maven.plugins:maven-resources-plugin:maven-plugin:3.0.2:runtime - org.apache.maven.plugins:maven-scm-plugin:maven-plugin:1.9.5:runtime - org.apache.maven.plugins:maven-site-plugin:maven-plugin:3.3:runtime - org.apache.maven.plugins:maven-surefire-plugin:maven-plugin:3.0.0-M1:runtime - org.codehaus.mojo:license-maven-plugin:maven-plugin:1.17:runtime - org.codehaus.mojo:versions-maven-plugin:maven-plugin:2.5:runtime +com.github.siom79.japicmp:japicmp-maven-plugin:maven-plugin:0.14.3:runtime +com.mycila:license-maven-plugin:maven-plugin:3.0:runtime +org.apache.felix:maven-bundle-plugin:maven-plugin:3.5.0:runtime +org.apache.maven.plugins:maven-assembly-plugin:maven-plugin:3.1.0:runtime +org.apache.maven.plugins:maven-clean-plugin:maven-plugin:2.5:runtime +org.apache.maven.plugins:maven-compiler-plugin:maven-plugin:3.7.0:runtime +org.apache.maven.plugins:maven-dependency-plugin:maven-plugin:3.0.2:runtime +org.apache.maven.plugins:maven-deploy-plugin:maven-plugin:2.8.2:runtime +org.apache.maven.plugins:maven-failsafe-plugin:maven-plugin:3.0.0-M4:runtime +org.apache.maven.plugins:maven-install-plugin:maven-plugin:2.5.2:runtime +org.apache.maven.plugins:maven-resources-plugin:maven-plugin:3.0.2:runtime +org.apache.maven.plugins:maven-scm-plugin:maven-plugin:1.9.5:runtime +org.apache.maven.plugins:maven-site-plugin:maven-plugin:3.3:runtime +org.apache.maven.plugins:maven-surefire-plugin:maven-plugin:3.0.0-M4:runtime +org.codehaus.mojo:flatten-maven-plugin:maven-plugin:1.0.1:runtime +org.codehaus.mojo:license-maven-plugin:maven-plugin:1.17:runtime +org.codehaus.mojo:versions-maven-plugin:maven-plugin:2.5:runtime +org.jacoco:jacoco-maven-plugin:maven-plugin:0.8.5:runtime diff --git a/legal/3rd-party-dependencies/provided.txt b/legal/3rd-party-dependencies/provided.txt index 08399945..ee0834c3 100644 --- a/legal/3rd-party-dependencies/provided.txt +++ b/legal/3rd-party-dependencies/provided.txt @@ -1 +1 @@ - com.google.code.findbugs:jsr305:jar:3.0.1:provided +com.google.code.findbugs:jsr305:jar:3.0.1:provided diff --git a/legal/3rd-party-dependencies/runtime.txt b/legal/3rd-party-dependencies/runtime.txt new file mode 100644 index 00000000..e69de29b diff --git a/legal/3rd-party-dependencies/test.txt b/legal/3rd-party-dependencies/test.txt index 3df71b89..bfa98253 100644 --- a/legal/3rd-party-dependencies/test.txt +++ b/legal/3rd-party-dependencies/test.txt @@ -1,41 +1,47 @@ - biz.aQute.bnd:bndlib:jar:2.4.0:test - ch.qos.logback:logback-classic:jar:1.2.3:test - ch.qos.logback:logback-core:jar:1.2.3:test - junit:junit:jar:4.12:test - net.bytebuddy:byte-buddy-agent:jar:1.7.0:test - net.bytebuddy:byte-buddy:jar:1.7.0:test - net.javacrumbs.json-unit:json-unit-core:jar:1.28.1:test - net.javacrumbs.json-unit:json-unit:jar:1.28.1:test - nl.jqno.equalsverifier:equalsverifier:jar:3.0.3:test - org.apache.felix:org.apache.felix.framework:jar:5.4.0:test - org.apache.servicemix.bundles:org.apache.servicemix.bundles.javax-inject:jar:1_2:test - org.assertj:assertj-core:jar:3.11.1:test - org.hamcrest:hamcrest-core:jar:1.3:test - org.json:json:jar:20090211:test - org.mockito:mockito-core:jar:2.9.0:test - org.mutabilitydetector:MutabilityDetector:jar:0.9.6:test - org.objenesis:objenesis:jar:2.6:test - org.ops4j.base:ops4j-base-io:jar:1.5.0:test - org.ops4j.base:ops4j-base-lang:jar:1.5.0:test - org.ops4j.base:ops4j-base-monitors:jar:1.5.0:test - org.ops4j.base:ops4j-base-net:jar:1.5.0:test - org.ops4j.base:ops4j-base-spi:jar:1.5.0:test - org.ops4j.base:ops4j-base-store:jar:1.5.0:test - org.ops4j.base:ops4j-base-util-property:jar:1.5.0:test - org.ops4j.pax.exam:pax-exam-container-native:jar:4.8.0:test - org.ops4j.pax.exam:pax-exam:jar:4.8.0:test - org.ops4j.pax.exam:pax-exam-junit4:jar:4.8.0:test - org.ops4j.pax.exam:pax-exam-link-mvn:jar:4.8.0:test - org.ops4j.pax.exam:pax-exam-spi:jar:4.8.0:test - org.ops4j.pax.swissbox:pax-swissbox-core:jar:1.8.2:test - org.ops4j.pax.swissbox:pax-swissbox-lifecycle:jar:1.8.2:test - org.ops4j.pax.swissbox:pax-swissbox-optional-jcl:jar:1.8.2:test - org.ops4j.pax.swissbox:pax-swissbox-property:jar:1.8.2:test - org.ops4j.pax.swissbox:pax-swissbox-tracker:jar:1.8.2:test - org.ops4j.pax.tinybundles:tinybundles:jar:2.1.1:test - org.ops4j.pax.url:pax-url-aether:jar:2.4.2:test - org.ops4j.pax.url:pax-url-classpath:jar:2.4.2:test - org.ops4j.pax.url:pax-url-commons:jar:2.4.2:test - org.ops4j.pax.url:pax-url-link:jar:2.4.2:test - org.skyscreamer:jsonassert:jar:1.2.3:test - org.slf4j:jcl-over-slf4j:jar:1.6.6:test +biz.aQute.bnd:bndlib:jar:2.4.0:test +ch.qos.logback:logback-classic:jar:1.2.3:test +ch.qos.logback:logback-core:jar:1.2.3:test +com.beust:jcommander:jar:1.72:test +junit:junit:jar:4.12:test +net.bytebuddy:byte-buddy-agent:jar:1.9.10:test +net.bytebuddy:byte-buddy:jar:1.9.10:test +net.javacrumbs.json-unit:json-unit-core:jar:1.28.1:test +net.javacrumbs.json-unit:json-unit:jar:1.28.1:test +nl.jqno.equalsverifier:equalsverifier:jar:3.0.3:test +org.apache-extras.beanshell:bsh:jar:2.0b6:test +org.apache.felix:org.apache.felix.framework:jar:6.0.3:test +org.apache.servicemix.bundles:org.apache.servicemix.bundles.javax-inject:jar:1_2:test +org.assertj:assertj-core:jar:3.12.0:test +org.codehaus.mojo:animal-sniffer-annotations:jar:1.9:test +org.hamcrest:hamcrest-core:jar:1.3:test +org.json:json:jar:20090211:test +org.mockito:mockito-core:jar:3.1.0:test +org.mutabilitydetector:MutabilityDetector:jar:0.10.2:test +org.objenesis:objenesis:jar:2.6:test +org.ops4j.base:ops4j-base-io:jar:1.5.0:test +org.ops4j.base:ops4j-base-lang:jar:1.5.0:test +org.ops4j.base:ops4j-base-monitors:jar:1.5.0:test +org.ops4j.base:ops4j-base-net:jar:1.5.0:test +org.ops4j.base:ops4j-base-spi:jar:1.5.0:test +org.ops4j.base:ops4j-base-store:jar:1.5.0:test +org.ops4j.base:ops4j-base-util-property:jar:1.5.0:test +org.ops4j.pax.exam:pax-exam-container-native:jar:4.13.0:test +org.ops4j.pax.exam:pax-exam:jar:4.13.0:test +org.ops4j.pax.exam:pax-exam-junit4:jar:4.13.0:test +org.ops4j.pax.exam:pax-exam-link-mvn:jar:4.13.0:test +org.ops4j.pax.exam:pax-exam-spi:jar:4.13.0:test +org.ops4j.pax.swissbox:pax-swissbox-core:jar:1.8.2:test +org.ops4j.pax.swissbox:pax-swissbox-lifecycle:jar:1.8.2:test +org.ops4j.pax.swissbox:pax-swissbox-optional-jcl:jar:1.8.2:test +org.ops4j.pax.swissbox:pax-swissbox-property:jar:1.8.2:test +org.ops4j.pax.swissbox:pax-swissbox-tracker:jar:1.8.2:test +org.ops4j.pax.tinybundles:tinybundles:jar:2.1.1:test +org.ops4j.pax.url:pax-url-aether:jar:2.4.5:test +org.ops4j.pax.url:pax-url-classpath:jar:2.4.5:test +org.ops4j.pax.url:pax-url-commons:jar:2.4.5:test +org.ops4j.pax.url:pax-url-link:jar:2.4.5:test +org.reactivestreams:reactive-streams-examples:jar:1.0.3:test +org.reactivestreams:reactive-streams-tck:jar:1.0.3:test +org.skyscreamer:jsonassert:jar:1.2.3:test +org.slf4j:jcl-over-slf4j:jar:1.6.6:test +org.testng:test diff --git a/legal/NOTICE-THIRD-PARTY.md b/legal/NOTICE-THIRD-PARTY.md index ccbe5019..41512936 100644 --- a/legal/NOTICE-THIRD-PARTY.md +++ b/legal/NOTICE-THIRD-PARTY.md @@ -16,17 +16,25 @@ * Source: https://github.com/TakahikoKawasaki/nv-websocket-client -## Atteo Class Index (3.7) +## Atteo Class Index (3.8) - * Maven coordinates: `org.atteo.classindex:classindex:3.7` + * Maven coordinates: `org.atteo.classindex:classindex:3.8` * License: [Apache-2.0](licenses/Apache-2.0.txt) * Project: http://atteo.org/static/classindex/classindex * Source: https://github.com/atteo/classindex/classindex -## SLF4J API Module (1.7.25) +## reactive-streams (1.0.3) - * Maven coordinates: `org.slf4j:slf4j-api:1.7.25` + * Maven coordinates: `org.reactivestreams:reactive-streams:1.0.3` + * License: [CC0](licenses/CC0.txt) + * Project: http://www.reactive-streams.org/ + * Source: https://github.com/reactive-streams/reactive-streams + + +## SLF4J API Module (1.7.28) + + * Maven coordinates: `org.slf4j:slf4j-api:1.7.28` * License: [MIT](licenses/MIT.txt) * Project: http://www.slf4j.org * Source: https://github.com/qos-ch/slf4j/slf4j-api diff --git a/legal/licenses/CC0.txt b/legal/licenses/CC0.txt new file mode 100644 index 00000000..0e259d42 --- /dev/null +++ b/legal/licenses/CC0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. From ead6a1db3502e42ef3593a92d413f4d6f2580e7f Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Thu, 23 Apr 2020 11:21:34 +0200 Subject: [PATCH 20/23] updated cqs.md document Signed-off-by: Thomas Jaeckle --- legal/3rd-party-dependencies/cqs.md | 132 ++++++++++++++-------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/legal/3rd-party-dependencies/cqs.md b/legal/3rd-party-dependencies/cqs.md index 40730cd2..bcc191e6 100644 --- a/legal/3rd-party-dependencies/cqs.md +++ b/legal/3rd-party-dependencies/cqs.md @@ -19,69 +19,69 @@ | Group ID | Artifact ID | Version | CQ | |---|---|---|---| -|com.google.code.findbugs|jsr305|3.0.1| []() | -|biz.aQute.bnd|bndlib|2.4.0| []() | -|ch.qos.logback|logback-classic|1.2.3| []() | -|ch.qos.logback|logback-core|1.2.3| []() | -|com.beust|jcommander|1.72| []() | -|junit|junit|4.12| []() | -|net.bytebuddy|byte-buddy-agent|1.9.10| []() | -|net.bytebuddy|byte-buddy|1.9.10| []() | -|net.javacrumbs.json-unit|json-unit-core|1.28.1| []() | -|net.javacrumbs.json-unit|json-unit|1.28.1| []() | -|nl.jqno.equalsverifier|equalsverifier|3.0.3| []() | -|org.apache-extras.beanshell|bsh|2.0b6| []() | -|org.apache.felix|org.apache.felix.framework|6.0.3| []() | -|org.apache.servicemix.bundles|org.apache.servicemix.bundles.javax-inject|1_2| []() | -|org.assertj|assertj-core|3.12.0| []() | -|org.codehaus.mojo|animal-sniffer-annotations|1.9| []() | -|org.hamcrest|hamcrest-core|1.3| []() | -|org.json|json|20090211| []() | -|org.mockito|mockito-core|3.1.0| []() | -|org.mutabilitydetector|MutabilityDetector|0.10.2| []() | -|org.objenesis|objenesis|2.6| []() | -|org.ops4j.base|ops4j-base-io|1.5.0| []() | -|org.ops4j.base|ops4j-base-lang|1.5.0| []() | -|org.ops4j.base|ops4j-base-monitors|1.5.0| []() | -|org.ops4j.base|ops4j-base-net|1.5.0| []() | -|org.ops4j.base|ops4j-base-spi|1.5.0| []() | -|org.ops4j.base|ops4j-base-store|1.5.0| []() | -|org.ops4j.base|ops4j-base-util-property|1.5.0| []() | -|org.ops4j.pax.exam|pax-exam-container-native|4.13.0| []() | -|org.ops4j.pax.exam|pax-exam|4.13.0| []() | -|org.ops4j.pax.exam|pax-exam-junit4|4.13.0| []() | -|org.ops4j.pax.exam|pax-exam-link-mvn|4.13.0| []() | -|org.ops4j.pax.exam|pax-exam-spi|4.13.0| []() | -|org.ops4j.pax.swissbox|pax-swissbox-core|1.8.2| []() | -|org.ops4j.pax.swissbox|pax-swissbox-lifecycle|1.8.2| []() | -|org.ops4j.pax.swissbox|pax-swissbox-optional-jcl|1.8.2| []() | -|org.ops4j.pax.swissbox|pax-swissbox-property|1.8.2| []() | -|org.ops4j.pax.swissbox|pax-swissbox-tracker|1.8.2| []() | -|org.ops4j.pax.tinybundles|tinybundles|2.1.1| []() | -|org.ops4j.pax.url|pax-url-aether|2.4.5| []() | -|org.ops4j.pax.url|pax-url-classpath|2.4.5| []() | -|org.ops4j.pax.url|pax-url-commons|2.4.5| []() | -|org.ops4j.pax.url|pax-url-link|2.4.5| []() | -|org.reactivestreams|reactive-streams-examples|1.0.3| []() | -|org.reactivestreams|reactive-streams-tck|1.0.3| []() | -|org.skyscreamer|jsonassert|1.2.3| []() | -|org.slf4j|jcl-over-slf4j|1.6.6| []() | -|org.testng|test| []() | -|com.github.siom79.japicmp|japicmp-maven-plugin|0.14.3| []() | -|com.mycila|license-maven-plugin|3.0| []() | -|org.apache.felix|maven-bundle-plugin|3.5.0| []() | -|org.apache.maven.plugins|maven-assembly-plugin|3.1.0| []() | -|org.apache.maven.plugins|maven-clean-plugin|2.5| []() | -|org.apache.maven.plugins|maven-compiler-plugin|3.7.0| []() | -|org.apache.maven.plugins|maven-dependency-plugin|3.0.2| []() | -|org.apache.maven.plugins|maven-deploy-plugin|2.8.2| []() | -|org.apache.maven.plugins|maven-failsafe-plugin|3.0.0-M4| []() | -|org.apache.maven.plugins|maven-install-plugin|2.5.2| []() | -|org.apache.maven.plugins|maven-resources-plugin|3.0.2| []() | -|org.apache.maven.plugins|maven-scm-plugin|1.9.5| []() | -|org.apache.maven.plugins|maven-site-plugin|3.3| []() | -|org.apache.maven.plugins|maven-surefire-plugin|3.0.0-M4| []() | -|org.codehaus.mojo|flatten-maven-plugin|1.0.1| []() | -|org.codehaus.mojo|license-maven-plugin|1.17| []() | -|org.codehaus.mojo|versions-maven-plugin|2.5| []() | -|org.jacoco|jacoco-maven-plugin|0.8.5| []() | +|com.google.code.findbugs|jsr305|3.0.1| [14511](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=14511) | +|biz.aQute.bnd|bndlib|2.4.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|ch.qos.logback|logback-classic|1.2.3| [16305](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=16305) | +|ch.qos.logback|logback-core|1.2.3| [16305](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=16305) | +|com.beust|jcommander|1.72| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|junit|junit|4.12| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|net.bytebuddy|byte-buddy-agent|1.9.10| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|net.bytebuddy|byte-buddy|1.9.10| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|net.javacrumbs.json-unit|json-unit-core|1.28.1| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|net.javacrumbs.json-unit|json-unit|1.28.1| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|nl.jqno.equalsverifier|equalsverifier|3.0.3| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache-extras.beanshell|bsh|2.0b6| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.apache.felix|org.apache.felix.framework|6.0.3| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.apache.servicemix.bundles|org.apache.servicemix.bundles.javax-inject|1_2| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.assertj|assertj-core|3.12.0| [19841](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=19841) | +|org.codehaus.mojo|animal-sniffer-annotations|1.9| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.hamcrest|hamcrest-core|1.3| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.json|json|20090211| [19841](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=19841) | +|org.mockito|mockito-core|3.1.0| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.mutabilitydetector|MutabilityDetector|0.10.2| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.objenesis|objenesis|2.6| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.ops4j.base|ops4j-base-io|1.5.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.base|ops4j-base-lang|1.5.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.base|ops4j-base-monitors|1.5.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.base|ops4j-base-net|1.5.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.base|ops4j-base-spi|1.5.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.base|ops4j-base-store|1.5.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.base|ops4j-base-util-property|1.5.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.exam|pax-exam-container-native|4.13.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.exam|pax-exam|4.13.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.exam|pax-exam-junit4|4.13.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.exam|pax-exam-link-mvn|4.13.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.exam|pax-exam-spi|4.13.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.swissbox|pax-swissbox-core|1.8.2| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.swissbox|pax-swissbox-lifecycle|1.8.2| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.swissbox|pax-swissbox-optional-jcl|1.8.2| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.swissbox|pax-swissbox-property|1.8.2| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.swissbox|pax-swissbox-tracker|1.8.2| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.tinybundles|tinybundles|2.1.1| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.url|pax-url-aether|2.4.5| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.url|pax-url-classpath|2.4.5| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.url|pax-url-commons|2.4.5| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.ops4j.pax.url|pax-url-link|2.4.5| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.reactivestreams|reactive-streams-examples|1.0.3| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.reactivestreams|reactive-streams-tck|1.0.3| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.skyscreamer|jsonassert|1.2.3| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.slf4j|jcl-over-slf4j|1.6.6| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.testng|test|6.14.3| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|com.github.siom79.japicmp|japicmp-maven-plugin|0.14.3| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|com.mycila|license-maven-plugin|3.0| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.felix|maven-bundle-plugin|3.5.0| [21989](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=21989) | +|org.apache.maven.plugins|maven-assembly-plugin|3.1.0| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-clean-plugin|2.5| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-compiler-plugin|3.7.0| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-dependency-plugin|3.0.2| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-deploy-plugin|2.8.2| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-failsafe-plugin|3.0.0-M4| [19841](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=19841) | +|org.apache.maven.plugins|maven-install-plugin|2.5.2| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-resources-plugin|3.0.2| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-scm-plugin|1.9.5| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-site-plugin|3.3| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.apache.maven.plugins|maven-surefire-plugin|3.0.0-M4| [19841](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=19841) | +|org.codehaus.mojo|flatten-maven-plugin|1.0.1| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.codehaus.mojo|license-maven-plugin|1.17| [19841](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=19841) | +|org.codehaus.mojo|versions-maven-plugin|2.5| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | +|org.jacoco|jacoco-maven-plugin|0.8.5| [17676](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=17676) | From d4bb8a63672c5a3a8bcebc2fa5ad84dfa1cacd5d Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Thu, 23 Apr 2020 11:27:46 +0200 Subject: [PATCH 21/23] Issue eclipse/ditto#611: reverted changes to DittoClientUsageExamples Signed-off-by: Thomas Jaeckle --- .../client/DittoClientUsageExamples.java | 227 +++++++----------- 1 file changed, 89 insertions(+), 138 deletions(-) diff --git a/java/src/test/java/org/eclipse/ditto/client/DittoClientUsageExamples.java b/java/src/test/java/org/eclipse/ditto/client/DittoClientUsageExamples.java index 6c6bbc5e..4eff44e6 100755 --- a/java/src/test/java/org/eclipse/ditto/client/DittoClientUsageExamples.java +++ b/java/src/test/java/org/eclipse/ditto/client/DittoClientUsageExamples.java @@ -50,7 +50,6 @@ import org.eclipse.ditto.json.JsonFieldSelector; import org.eclipse.ditto.json.JsonObject; import org.eclipse.ditto.json.JsonValue; -import org.eclipse.ditto.model.base.acks.AcknowledgementLabel; import org.eclipse.ditto.model.base.common.HttpStatusCode; import org.eclipse.ditto.model.base.exceptions.DittoRuntimeException; import org.eclipse.ditto.model.base.json.JsonSchemaVersion; @@ -62,6 +61,8 @@ import org.eclipse.ditto.model.things.ThingBuilder; import org.eclipse.ditto.model.things.ThingId; import org.eclipse.ditto.model.things.ThingsModelFactory; +import org.eclipse.ditto.protocoladapter.JsonifiableAdaptable; +import org.eclipse.ditto.protocoladapter.ProtocolFactory; import org.eclipse.ditto.signals.commands.live.modify.CreateThingLiveCommandAnswerBuilder; import org.eclipse.ditto.signals.commands.live.modify.ModifyFeaturePropertyLiveCommandAnswerBuilder; import org.slf4j.Logger; @@ -77,8 +78,7 @@ public final class DittoClientUsageExamples { private static final Logger LOGGER = LoggerFactory.getLogger(DittoClientUsageExamples.class); - private static final String PROPERTIES_FILE = "ditto-client-starter-aws-dev.properties"; -// private static final String PROPERTIES_FILE = "ditto-client-starter-local.properties"; // for local development + private static final String PROPERTIES_FILE = "ditto-client-starter-local.properties"; // for local development // private static final String PROPERTIES_FILE = "ditto-client-starter-sandbox.properties"; private static final String PROXY_HOST; private static final String PROXY_PORT; @@ -98,154 +98,105 @@ public final class DittoClientUsageExamples { public static void main(final String... args) throws ExecutionException, InterruptedException { final DittoClient client = DittoClients.newInstance(createMessagingProvider()); -// final DittoClient client2 = DittoClients.newInstance(createMessagingProvider()); + final DittoClient client2 = DittoClients.newInstance(createMessagingProvider()); if (shouldNotSkip("twin.examples")) { -// final JsonifiableAdaptable jsonifiableAdaptable = ProtocolFactory.jsonifiableAdaptableFromJson( -// JsonFactory.readFrom("{\n" + -// " \"topic\": \"org.eclipse.ditto/xdk_53/things/twin/commands/modify\",\n" + -// " \"headers\": {},\n" + -// " \"path\": \"/\",\n" + -// " \"value\": {\n" + -// " \"thingId\": \"org.eclipse.ditto:xdk_53\",\n" + -// " \"attributes\": {\n" + -// " \"location\": {\n" + -// " \"latitude\": 44.673856,\n" + -// " \"longitude\": 8.261719\n" + -// " }\n" + -// " },\n" + -// " \"features\": {\n" + -// " \"accelerometer\": {\n" + -// " \"properties\": {\n" + -// " \"x\": 3.141,\n" + -// " \"y\": 2.718,\n" + -// " \"z\": 1,\n" + -// " \"unit\": \"g\"\n" + -// " }\n" + -// " }\n" + -// " }\n" + -// " }\n" + -// "}").asObject()); -// client.sendDittoProtocol(jsonifiableAdaptable).whenComplete((a, t) -> { -// if (a != null) { -// LOGGER.info("sendDittoProtocol: Received adaptable as response: {}", a); -// } -// if (t != null) { -// LOGGER.warn("sendDittoProtocol: Received throwable as response", t); -// } -// }); + final JsonifiableAdaptable jsonifiableAdaptable = ProtocolFactory.jsonifiableAdaptableFromJson( + JsonFactory.readFrom("{\n" + + " \"topic\": \"org.eclipse.ditto/xdk_53/things/twin/commands/modify\",\n" + + " \"headers\": {},\n" + + " \"path\": \"/\",\n" + + " \"value\": {\n" + + " \"thingId\": \"org.eclipse.ditto:xdk_53\",\n" + + " \"attributes\": {\n" + + " \"location\": {\n" + + " \"latitude\": 44.673856,\n" + + " \"longitude\": 8.261719\n" + + " }\n" + + " },\n" + + " \"features\": {\n" + + " \"accelerometer\": {\n" + + " \"properties\": {\n" + + " \"x\": 3.141,\n" + + " \"y\": 2.718,\n" + + " \"z\": 1,\n" + + " \"unit\": \"g\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}").asObject()); + client.sendDittoProtocol(jsonifiableAdaptable).whenComplete((a, t) -> { + if (a != null) { + LOGGER.info("sendDittoProtocol: Received adaptable as response: {}", a); + } + if (t != null) { + LOGGER.warn("sendDittoProtocol: Received throwable as response", t); + } + }); client.twin().startConsumption().get(); -// client2.twin().startConsumption().get(); + client2.twin().startConsumption().get(); LOGGER.info("Subscribed for Twin events"); client.live().startConsumption().get(); -// client2.live().startConsumption().get(); + client2.live().startConsumption().get(); LOGGER.info("Subscribed for Live events/commands/messages"); - client.twin().registerForThingChanges("th", change -> { - LOGGER.info("Got thing change: {}", change); - change.handleAcknowledgementRequest(AcknowledgementLabel.of("my-custom-ack"), handle -> - handle.acknowledge(HttpStatusCode.OK, JsonObject.newBuilder() - .set("outcome", JsonValue.of("thing")) - .build() - ) - ); - change.handleAcknowledgementRequest(AcknowledgementLabel.of("websocket"), handle -> - handle.acknowledge(HttpStatusCode.OK, JsonObject.newBuilder() - .set("outcome", JsonValue.of("I am WebSocket!")) - .build() - ) - ); - }); + System.out.println("\n\nContinuing with TWIN commands/events demo:"); + useTwinCommandsAndEvents(client, client2); + System.out.println("\n\nFinished with TWIN commands/events demo"); + } - client.twin().registerForFeatureChanges("fo", change -> { - LOGGER.info("Got feature change: {}", change); - change.handleAcknowledgementRequest(AcknowledgementLabel.of("my-custom-feature"), handle -> - handle.acknowledge(HttpStatusCode.OK, JsonObject.newBuilder() - .set("outcome", JsonValue.of("feature")) - .build() - ) - ); - }); + if (shouldNotSkip("live.examples")) { + client.live().startConsumption().get(); + client2.live().startConsumption().get(); - client.twin().registerForAttributesChanges("at", change -> { - LOGGER.info("Got attribute change: {}", change); - change.handleAcknowledgementRequest(AcknowledgementLabel.of("my-custom-attribute"), handle -> - handle.acknowledge(HttpStatusCode.CREATED, JsonObject.newBuilder() - .set("outcome", JsonValue.of("attribute")) - .build() - ) - ); - }); + System.out.println("\n\nAbout to continue with LIVE commands/events demo:"); + promptEnterKey(); + + useLiveCommands(client, client2); + System.out.println("\n\nFinished with LIVE commands/events demo"); + + System.out.println("\n\nAbout to continue with LIVE messages demo:"); + promptEnterKey(); + + useLiveMessages(client, client2); + System.out.println("\n\nFinished with LIVE messages demo"); + Thread.sleep(500); + } + + if (shouldNotSkip("search.examples")) { + System.out.println("\n\nAbout to continue with search commands:"); + promptEnterKey(); + useSearchCommands(client); + System.out.println("\n\nFinished with SEARCH commands demo"); + Thread.sleep(500); + } + + if (shouldNotSkip("load.test")) { + System.out.println("\n\nAbout to continue with small load test:"); + promptEnterKey(); + + final int loadTestThings = 100; + final int loadTestCount = 10; + subscribeForLoadTestUpdateChanges(client2, loadTestCount * loadTestThings, false); + performLoadTestUpdate(client, loadTestCount, loadTestThings, false); + performLoadTestRead(client, loadTestCount, true); + Thread.sleep(1000); + } -// final ThingId thingId = ThingId.inDefaultNamespace(UUID.randomUUID().toString()); -// client2.twin().create(thingId).get(); -// client2.twin().forId(thingId).putAttribute("test", 42, Options.dittoHeaders( -// DittoHeaders.newBuilder() -// .acknowledgementRequest(AcknowledgementRequest.of(DittoAcknowledgementLabel.PERSISTED), -// AcknowledgementRequest.of(AcknowledgementLabel.of("my-custom-attribute")) -// ) -// .build() -// )).whenComplete((v, t) -> { -// System.out.println("V: " + v); -// System.out.println("t: " + t); -// }); - -// System.out.println("\n\nContinuing with TWIN commands/events demo:"); -// useTwinCommandsAndEvents(client, client2); -// System.out.println("\n\nFinished with TWIN commands/events demo"); + if (shouldNotSkip("policies.examples")) { + System.out.println("\n\nAbout to continue with policy example:"); + promptEnterKey(); + addNewSubjectToExistingPolicy(client); + System.out.println("\n\nFinished with policy example"); } -// if (shouldNotSkip("live.examples")) { -// client.live().startConsumption().get(); -// client2.live().startConsumption().get(); -// -// System.out.println("\n\nAbout to continue with LIVE commands/events demo:"); -// promptEnterKey(); -// -// useLiveCommands(client, client2); -// System.out.println("\n\nFinished with LIVE commands/events demo"); -// -// System.out.println("\n\nAbout to continue with LIVE messages demo:"); -// promptEnterKey(); -// -// useLiveMessages(client, client2); -// System.out.println("\n\nFinished with LIVE messages demo"); -// Thread.sleep(500); -// } -// -// if (shouldNotSkip("search.examples")) { -// System.out.println("\n\nAbout to continue with search commands:"); -// promptEnterKey(); -// useSearchCommands(client); -// System.out.println("\n\nFinished with SEARCH commands demo"); -// Thread.sleep(500); -// } -// -// if (shouldNotSkip("load.test")) { -// System.out.println("\n\nAbout to continue with small load test:"); -// promptEnterKey(); -// -// final int loadTestThings = 100; -// final int loadTestCount = 10; -// subscribeForLoadTestUpdateChanges(client2, loadTestCount * loadTestThings, false); -// performLoadTestUpdate(client, loadTestCount, loadTestThings, false); -// performLoadTestRead(client, loadTestCount, true); -// Thread.sleep(1000); -// } -// -// if (shouldNotSkip("policies.examples")) { -// System.out.println("\n\nAbout to continue with policy example:"); -// promptEnterKey(); -// addNewSubjectToExistingPolicy(client); -// System.out.println("\n\nFinished with policy example"); -// } - -// client.destroy(); -// client2.destroy(); -// System.out.println("\n\nDittoClientUsageExamples successfully completed!"); -// System.exit(0); + client.destroy(); + client2.destroy(); + System.out.println("\n\nDittoClientUsageExamples successfully completed!"); + System.exit(0); } private static void addNewSubjectToExistingPolicy(final DittoClient client) @@ -770,7 +721,7 @@ private static MessagingProvider createMessagingProvider() { AuthenticationProviders.dummy(DummyAuthenticationConfiguration.newBuilder() .dummyUsername(DITTO_DUMMY_AUTH_USER) .build()); - } else if (DITTO_OAUTH_CLIENT_ID != null && !DITTO_OAUTH_CLIENT_ID.isEmpty()) { + } else if (DITTO_OAUTH_CLIENT_ID != null) { final ClientCredentialsAuthenticationConfiguration.ClientCredentialsAuthenticationConfigurationBuilder authenticationConfigurationBuilder = ClientCredentialsAuthenticationConfiguration.newBuilder() From 4b257364bf60b74f6362dae0547b9b6579e28abe Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Thu, 23 Apr 2020 16:05:04 +0200 Subject: [PATCH 22/23] provide the possibility to define additional DittoHeaders to be included when sending/replying to a message * fixed critical bug in PendingMessageImpl which caused a non-visible ClassCastException for message responses using the typed message send() API Signed-off-by: Thomas Jaeckle --- .../live/internal/PendingMessageImpl.java | 58 ++++++++++--------- .../client/live/messages/MessageSender.java | 11 ++++ .../internal/ImmutableMessageSender.java | 28 +++++++-- .../internal/WebSocketMessagingProvider.java | 2 +- 4 files changed, 65 insertions(+), 34 deletions(-) diff --git a/java/src/main/java/org/eclipse/ditto/client/live/internal/PendingMessageImpl.java b/java/src/main/java/org/eclipse/ditto/client/live/internal/PendingMessageImpl.java index 26dcb0a1..973bd094 100644 --- a/java/src/main/java/org/eclipse/ditto/client/live/internal/PendingMessageImpl.java +++ b/java/src/main/java/org/eclipse/ditto/client/live/internal/PendingMessageImpl.java @@ -107,37 +107,41 @@ private static void typeCheckAndConsume(final MessageResponseConsumer respons final BiConsumer uncheckedResponseConsumer = responseConsumer.getResponseConsumer(); final Class responseType = responseConsumer.getResponseType(); - // throw ClassCastException if response has incorrect type - final Message responseMessage; - if (response instanceof MessageCommand) { - responseMessage = ((MessageCommand) response).getMessage(); - } else if (response instanceof MessageCommandResponse) { - responseMessage = ((MessageCommandResponse) response).getMessage(); - } else if (response instanceof ErrorResponse) { - uncheckedResponseConsumer.accept(null, ((ErrorResponse) response).getDittoRuntimeException()); - return; - } else { - uncheckedResponseConsumer.accept(null, classCastException(responseType, response)); - return; - } + try { + // throw ClassCastException if response has incorrect type + final Message responseMessage; + if (response instanceof MessageCommand) { + responseMessage = ((MessageCommand) response).getMessage(); + } else if (response instanceof MessageCommandResponse) { + responseMessage = ((MessageCommandResponse) response).getMessage(); + } else if (response instanceof ErrorResponse) { + uncheckedResponseConsumer.accept(null, ((ErrorResponse) response).getDittoRuntimeException()); + return; + } else { + uncheckedResponseConsumer.accept(null, classCastException(responseType, response)); + return; + } - if (responseConsumer.getResponseType().isAssignableFrom(ByteBuffer.class)) { - uncheckedResponseConsumer.accept(asByteBufferMessage(responseMessage), null); - } else { - final Optional payloadOptional = responseMessage.getPayload(); - if (payloadOptional.isPresent()) { - final Object payload = payloadOptional.get(); - if (responseConsumer.getResponseType().isInstance(payload)) { - uncheckedResponseConsumer.accept(payload, null); + if (responseConsumer.getResponseType().isAssignableFrom(ByteBuffer.class)) { + uncheckedResponseConsumer.accept(asByteBufferMessage(responseMessage), null); + } else { + final Optional payloadOptional = responseMessage.getPayload(); + if (payloadOptional.isPresent()) { + final Object payload = payloadOptional.get(); + if (responseConsumer.getResponseType().isInstance(payload)) { + uncheckedResponseConsumer.accept(setMessagePayload(responseMessage, payload), null); + } else { + // response has unexpected type + uncheckedResponseConsumer.accept(setMessagePayload(responseMessage, null), + classCastException(responseType, payload)); + } } else { - // response has unexpected type - uncheckedResponseConsumer.accept(setMessagePayload(responseMessage, null), - classCastException(responseType, payload)); + // response has no payload; regard it as any message type + uncheckedResponseConsumer.accept(responseMessage, null); } - } else { - // response has no payload; regard it as any message type - uncheckedResponseConsumer.accept(responseMessage, null); } + } catch (final RuntimeException e) { + uncheckedResponseConsumer.accept(null, e); } } diff --git a/java/src/main/java/org/eclipse/ditto/client/live/messages/MessageSender.java b/java/src/main/java/org/eclipse/ditto/client/live/messages/MessageSender.java index 27d03a67..409829b6 100755 --- a/java/src/main/java/org/eclipse/ditto/client/live/messages/MessageSender.java +++ b/java/src/main/java/org/eclipse/ditto/client/live/messages/MessageSender.java @@ -19,6 +19,7 @@ import java.util.function.Consumer; import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.messages.Message; import org.eclipse.ditto.model.things.ThingId; @@ -152,6 +153,16 @@ interface SetPayloadOrSend extends MessageSendable { */ SetPayloadOrSend statusCode(HttpStatusCode statusCode); + /** + * Sets additional headers to send in the message. + * + * @param additionalHeaders the headers. + * @return fluent api builder that provides the functionality to set optionally fields of the message + * or send the message. + * @since 1.1.0 + */ + SetPayloadOrSend headers(DittoHeaders additionalHeaders); + /** * Sets the payload of the message. NOTE: The maximum payload size is restricted to 10MB. * diff --git a/java/src/main/java/org/eclipse/ditto/client/live/messages/internal/ImmutableMessageSender.java b/java/src/main/java/org/eclipse/ditto/client/live/messages/internal/ImmutableMessageSender.java index 324a5d51..16f303ac 100755 --- a/java/src/main/java/org/eclipse/ditto/client/live/messages/internal/ImmutableMessageSender.java +++ b/java/src/main/java/org/eclipse/ditto/client/live/messages/internal/ImmutableMessageSender.java @@ -24,6 +24,7 @@ import org.eclipse.ditto.client.live.messages.MessageSender; import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.messages.Message; import org.eclipse.ditto.model.messages.MessageBuilder; import org.eclipse.ditto.model.messages.MessageDirection; @@ -56,6 +57,7 @@ public final class ImmutableMessageSender implements MessageSender { private String messageCorrelationId; private String messageContentType; private HttpStatusCode messageStatusCode; + private DittoHeaders messageAdditionalHeaders; private Consumer> sendConsumer; private ImmutableMessageSender(final boolean isResponse) { @@ -69,6 +71,7 @@ private ImmutableMessageSender(final boolean isResponse) { messageTimestamp = null; messageCorrelationId = null; messageStatusCode = null; + messageAdditionalHeaders = null; } /** @@ -128,12 +131,19 @@ private void buildAndSendMessage(final T payload) { private void buildAndSendMessage(final T payload, final MessageResponseConsumer responseConsumer) { final MessageHeadersBuilder messageHeadersBuilder = - MessageHeaders.newBuilder(messageDirection, messageThingId, messageSubject) - .contentType(messageContentType) - .featureId(messageFeatureId) - .timeout(messageTimeout) - .timestamp(messageTimestamp) - .correlationId(messageCorrelationId); + MessageHeaders.newBuilder(messageDirection, messageThingId, messageSubject); + + if (null != messageAdditionalHeaders) { + // put additionalHeaders first, so that custom "contentType", "timeout", etc. still overwrites the values: + messageHeadersBuilder.putHeaders(messageAdditionalHeaders); + } + + messageHeadersBuilder + .contentType(messageContentType) + .featureId(messageFeatureId) + .timeout(messageTimeout) + .timestamp(messageTimestamp) + .correlationId(messageCorrelationId); if (responseConsumer == null) { messageHeadersBuilder.responseRequired(false); @@ -222,6 +232,12 @@ public SetPayloadOrSend statusCode(final HttpStatusCode statusCode) { return this; } + @Override + public SetPayloadOrSend headers(final DittoHeaders additionalHeaders) { + messageAdditionalHeaders = additionalHeaders; + return this; + } + @Override public SetContentType payload(final T payload) { return new SetContentTypeImpl(payload); diff --git a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java index 82f1da74..c3483613 100644 --- a/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java +++ b/java/src/main/java/org/eclipse/ditto/client/messaging/internal/WebSocketMessagingProvider.java @@ -457,7 +457,7 @@ public void onBinaryMessage(final WebSocket websocket, final byte[] binary) { @Override public void onTextMessage(final WebSocket websocket, final String text) { callbackExecutor.execute(() -> { - LOGGER.trace("Client <{}>: Received WebSocket string message <{}>", sessionId, text); + LOGGER.debug("Client <{}>: Received WebSocket string message <{}>", sessionId, text); handleIncomingMessage(text); }); } From a9789767223aab05e8d67d81be0a1f0b75bc59fc Mon Sep 17 00:00:00 2001 From: Thomas Jaeckle Date: Mon, 27 Apr 2020 11:59:54 +0200 Subject: [PATCH 23/23] Issue eclipse/ditto#611: fixed usage of dependency: ditto-signals-acks-things is required Signed-off-by: Thomas Jaeckle --- java/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/pom.xml b/java/pom.xml index cdf9e43b..86016d9d 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -829,7 +829,7 @@
org.eclipse.ditto - ditto-signals-acks + ditto-signals-acks-things ${ditto.version}