Skip to content

Commit

Permalink
Add connectivity announcements for when a connection was opened or cl…
Browse files Browse the repository at this point in the history
…osed

Signed-off-by: Florian Fendt <Florian.Fendt@bosch.io>
  • Loading branch information
ffendt committed May 4, 2021
1 parent c5ee5b8 commit 060c0ef
Show file tree
Hide file tree
Showing 11 changed files with 877 additions and 0 deletions.
5 changes: 5 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,11 @@
<artifactId>ditto-signals-announcements-policies</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.ditto</groupId>
<artifactId>ditto-signals-announcements-connectivity</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.eclipse.ditto</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static ConnectionId generateRandom() {
*
* @param connectionId the connection id.
* @return the connection ID.
* @throws ConnectionIdInvalidException if the provided {@code connectionId} is of invalid format.
*/
public static ConnectionId of(final CharSequence connectionId) {
if (connectionId instanceof ConnectionId) {
Expand Down
63 changes: 63 additions & 0 deletions signals/announcements/connectivity/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2021 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
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.ditto</groupId>
<artifactId>ditto-signals-announcements</artifactId>
<version>${revision}</version>
</parent>

<artifactId>ditto-signals-announcements-connectivity</artifactId>
<name>Eclipse Ditto :: Signals :: Announcements :: Connectivity</name>
<packaging>bundle</packaging>

<dependencies>
<dependency>
<groupId>org.eclipse.ditto</groupId>
<artifactId>ditto-signals-announcements-base</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.ditto</groupId>
<artifactId>ditto-model-connectivity</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
org.atteo.classindex,
!org.eclipse.ditto.utils.jsr305.annotations,
org.eclipse.ditto.*
</Import-Package>
<Export-Package>
org.eclipse.ditto.signals.announcements.connectivity
</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright (c) 2021 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.signals.announcements.connectivity;

import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull;

import java.text.MessageFormat;
import java.util.Objects;
import java.util.function.Predicate;

import org.eclipse.ditto.json.JsonExceptionBuilder;
import org.eclipse.ditto.json.JsonField;
import org.eclipse.ditto.json.JsonFieldDefinition;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonObjectBuilder;
import org.eclipse.ditto.json.JsonParseException;
import org.eclipse.ditto.json.JsonPointer;
import org.eclipse.ditto.model.base.headers.DittoHeaders;
import org.eclipse.ditto.model.connectivity.ConnectionId;
import org.eclipse.ditto.model.connectivity.ConnectionIdInvalidException;
import org.eclipse.ditto.signals.announcements.base.AbstractAnnouncement;

/**
* Abstract superclass of connectivity announcements.
*
* @param <T> type of a concrete subclass.
* @since 2.1.0
*/
public abstract class AbstractConnectivityAnnouncement<T extends AbstractConnectivityAnnouncement<T>>
extends AbstractAnnouncement<T>
implements ConnectivityAnnouncement<T> {

private final ConnectionId connectionId;

/**
* Create a connectivity announcement object.
*
* @param connectionId the connection ID.
* @param dittoHeaders the Ditto headers.
*/
protected AbstractConnectivityAnnouncement(final ConnectionId connectionId, final DittoHeaders dittoHeaders) {
super(dittoHeaders);
this.connectionId = checkNotNull(connectionId, "connectionId");
}

protected static ConnectionId deserializeConnectionId(final JsonObject jsonObject) {
final JsonFieldDefinition<String> fieldDefinition = ConnectivityAnnouncement.JsonFields.JSON_CONNECTION_ID;
final String connectionIdJsonValue = jsonObject.getValueOrThrow(fieldDefinition);
try {
return ConnectionId.of(connectionIdJsonValue);
} catch (final ConnectionIdInvalidException e) {
throw getJsonParseException(fieldDefinition, ConnectionId.class, e);
}
}

protected static JsonParseException getJsonParseException(final JsonFieldDefinition<?> fieldDefinition,
final Class<?> targetClass, final Throwable cause) {
return getJsonParseExceptionBuilder(fieldDefinition, targetClass, cause)
.build();
}

protected static JsonExceptionBuilder<JsonParseException> getJsonParseExceptionBuilder(
final JsonFieldDefinition<?> fieldDefinition, final Class<?> targetClass, final Throwable cause) {

return JsonParseException.newBuilder()
.message(MessageFormat.format("Failed to deserialize field <{0}> as {1}: {2}",
fieldDefinition.getPointer(),
targetClass.getName(),
cause.getMessage()))
.cause(cause);
}

/**
* Append {@code ConnectivityAnnouncement}-specific payload to the passed {@code jsonObjectBuilder}.
*
* @param jsonObjectBuilder the JsonObjectBuilder to add the payload to.
* @param predicate the predicate to evaluate when adding the payload.
*/
protected abstract void appendConnectivityAnnouncementPayload(JsonObjectBuilder jsonObjectBuilder,
Predicate<JsonField> predicate);

@Override
public ConnectionId getEntityId() {
return connectionId;
}

@Override
public JsonPointer getResourcePath() {
return JsonPointer.empty();
}

@Override
public String getResourceType() {
return RESOURCE_TYPE;
}

@Override
protected void appendPayload(final JsonObjectBuilder jsonObjectBuilder, final Predicate<JsonField> predicate) {
jsonObjectBuilder.set(ConnectivityAnnouncement.JsonFields.JSON_CONNECTION_ID, connectionId.toString());
appendConnectivityAnnouncementPayload(jsonObjectBuilder, predicate);
}

@Override
public String toString() {
return super.toString() + ", connectionId=" + connectionId;
}

@Override
public boolean equals(final Object other) {
if (super.equals(other)) {
return Objects.equals(((AbstractConnectivityAnnouncement<?>) other).connectionId, connectionId);
} else {
return false;
}
}

@Override
public int hashCode() {
return Objects.hash(connectionId, super.hashCode());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Copyright (c) 2021 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.signals.announcements.connectivity;

import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull;

import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.Objects;
import java.util.function.Predicate;

import javax.annotation.concurrent.Immutable;

import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonField;
import org.eclipse.ditto.json.JsonFieldDefinition;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonObjectBuilder;
import org.eclipse.ditto.json.JsonParseException;
import org.eclipse.ditto.json.JsonPointer;
import org.eclipse.ditto.model.base.headers.DittoHeaders;
import org.eclipse.ditto.model.base.json.FieldType;
import org.eclipse.ditto.model.base.json.JsonParsableAnnouncement;
import org.eclipse.ditto.model.base.json.JsonSchemaVersion;
import org.eclipse.ditto.model.connectivity.ConnectionId;

/**
* Announcement that a connection was closed by a user (by setting its target status to 'closed').
*
* @since 2.1.0
*/
@Immutable
@JsonParsableAnnouncement(type = ConnectionClosedAnnouncement.TYPE)
public final class ConnectionClosedAnnouncement extends AbstractConnectivityAnnouncement<ConnectionClosedAnnouncement> {

private static final String NAME = "closed";

/**
* Type of this announcement.
*/
public static final String TYPE = TYPE_PREFIX + NAME;

private final Instant closedAt;

private ConnectionClosedAnnouncement(final ConnectionId connectionId, final Instant closedAt,
final DittoHeaders dittoHeaders) {
super(connectionId, dittoHeaders);
this.closedAt = checkNotNull(closedAt, "closedAt");
}

/**
* Create a announcement for connection closing.
*
* @param connectionId the connection ID.
* @param closedAt when the connection was closed.
* @param dittoHeaders headers of the announcement.
* @return the announcement.
*/
public static ConnectionClosedAnnouncement of(final ConnectionId connectionId, final Instant closedAt,
final DittoHeaders dittoHeaders) {

return new ConnectionClosedAnnouncement(connectionId, closedAt, dittoHeaders);
}

/**
* Deserialize a connection-closed announcement from JSON.
*
* @param jsonObject the serialized JSON.
* @param dittoHeaders the Ditto headers.
* @return the deserialized {@code ConnectionClosedAnnouncement}.
* @throws NullPointerException if any argument is {@code null}.
* @throws JsonParseException if the passed in {@code jsonObject} was not in the expected
* 'ConnectionClosedAnnouncement' format.
*/
public static ConnectionClosedAnnouncement fromJson(final JsonObject jsonObject, final DittoHeaders dittoHeaders) {
final ConnectionId connectionId = deserializeConnectionId(jsonObject);
final Instant closedAt = deserializeClosedAt(jsonObject);
return of(connectionId, closedAt, dittoHeaders);
}

private static Instant deserializeClosedAt(final JsonObject jsonObject) {
final JsonFieldDefinition<String> fieldDefinition = JsonFields.CLOSED_AT;
final String closeddAtJsonValue = jsonObject.getValueOrThrow(fieldDefinition);
try {
return Instant.parse(closeddAtJsonValue);
} catch (final DateTimeParseException e) {
throw getJsonParseExceptionBuilder(fieldDefinition, Instant.class, e)
.description("Closed timestamp must be provided as ISO-8601 formatted char sequence.")
.build();
}
}

@Override
public ConnectionClosedAnnouncement setDittoHeaders(final DittoHeaders dittoHeaders) {
return new ConnectionClosedAnnouncement(getEntityId(), closedAt, dittoHeaders);
}

@Override
protected void appendConnectivityAnnouncementPayload(final JsonObjectBuilder jsonObjectBuilder,
final Predicate<JsonField> predicate) {

jsonObjectBuilder.set(JsonFields.CLOSED_AT, closedAt.toString(), predicate);
}

@Override
public JsonPointer getResourcePath() {
return JsonPointer.empty();
}

@Override
public String getResourceType() {
return RESOURCE_TYPE;
}

@Override
public String getType() {
return TYPE;
}

@Override
public String getName() {
return NAME;
}

/**
* Get the timestamp when the connection was closed.
*
* @return the connection close timestamp.
*/
public Instant getClosedAt() {
return closedAt;
}

@Override
public String toString() {
return getClass().getSimpleName() + "[" + super.toString() +
", closedAt=" + closedAt +
"]";
}

@Override
public boolean equals(final Object other) {
if (super.equals(other)) {
final ConnectionClosedAnnouncement that = (ConnectionClosedAnnouncement) other;
return Objects.equals(closedAt, that.closedAt);
} else {
return false;
}
}

@Override
public int hashCode() {
return Objects.hash(closedAt, super.hashCode());
}

/**
* JSON fields of this announcement's payload for use in the Ditto protocol.
*/
public static final class JsonFields {

/**
* JSON field for the timestamp when the connection was closed.
*/
public static final JsonFieldDefinition<String> CLOSED_AT =
JsonFactory.newStringFieldDefinition("closedAt", JsonSchemaVersion.V_2, FieldType.REGULAR);

private JsonFields() {
throw new AssertionError();
}

}

}
Loading

0 comments on commit 060c0ef

Please sign in to comment.