Skip to content

Commit

Permalink
Merge pull request #56 from bosch-io/feature/e2e_ack
Browse files Browse the repository at this point in the history
End-2-end acks for Ditto Java Client
  • Loading branch information
thjaeckle authored Apr 27, 2020
2 parents e9d3720 + a978976 commit 71c29a4
Show file tree
Hide file tree
Showing 79 changed files with 2,037 additions and 790 deletions.
11 changes: 9 additions & 2 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M1</version>
<version>3.0.0-M4</version>
<configuration>
<systemProperties>
<kamon.auto-start>true</kamon.auto-start>
Expand All @@ -345,7 +345,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M1</version>
<version>3.0.0-M4</version>
<executions>
<execution>
<id>integration-test</id>
Expand Down Expand Up @@ -445,6 +445,8 @@
<exclude>org.eclipse.ditto.client.messaging.internal</exclude>
<exclude>org.eclipse.ditto.client.options.internal</exclude>
<exclude>org.eclipse.ditto.client.twin.internal</exclude>
<!-- this builder is an internal implementation of a builder interface and should not be handled as API: -->
<exclude>org.eclipse.ditto.client.configuration.ClientCredentialsAuthenticationConfiguration$ClientCredentialsAuthenticationConfigurationBuilder</exclude>
</excludes>
</parameter>
</configuration>
Expand Down Expand Up @@ -825,6 +827,11 @@
<artifactId>ditto-signals-base</artifactId>
<version>${ditto.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.ditto</groupId>
<artifactId>ditto-signals-acks-things</artifactId>
<version>${ditto.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.ditto</groupId>
<artifactId>ditto-signals-commands-base</artifactId>
Expand Down
2 changes: 2 additions & 0 deletions java/src/main/assembly/assembly.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
<include>org.eclipse.ditto:ditto-model-things</include>
<include>org.eclipse.ditto:ditto-model-thingsearch</include>
<include>org.eclipse.ditto:ditto-signals-base</include>
<include>org.eclipse.ditto:ditto-signals-acks-base</include>
<include>org.eclipse.ditto:ditto-signals-acks-things</include>
<include>org.eclipse.ditto:ditto-signals-commands-base</include>
<include>org.eclipse.ditto:ditto-signals-commands-thingsearch</include>
<include>org.eclipse.ditto:ditto-signals-commands-things</include>
Expand Down
Original file line number Diff line number Diff line change
@@ -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<AcknowledgementRequestHandle> {

/**
* 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);

}
47 changes: 44 additions & 3 deletions java/src/main/java/org/eclipse/ditto/client/changes/Change.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,26 @@
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;

/**
* Common interface for all Thing related changes.
*
* @since 1.0.0
*/
public interface Change extends WithId {
public interface Change extends WithId, WithEntityType, WithDittoHeaders<Change> {

/**
* Returns the {@link ChangeAction} which caused this change.
Expand Down Expand Up @@ -88,19 +93,55 @@ 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<JsonObject> getExtra();

/**
* 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<Collection<AcknowledgementRequestHandle>> 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<AcknowledgementRequestHandle> acknowledgementHandle);

}
Original file line number Diff line number Diff line change
@@ -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<Acknowledgement> 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<Acknowledgement> 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 +
"]";
}
}
Loading

0 comments on commit 71c29a4

Please sign in to comment.