Skip to content

Commit

Permalink
#898: restructured DittoProtocolAdapter to be able to determine the T…
Browse files Browse the repository at this point in the history
…opicPath for a given Signal

* move "instanceof" cascade to DefaultAdapterResolver to make it reusable
* simplified DittoProtocolAdapter, removed non-needed overloaded methods
* added SignalMapper implementations for ThingEvents and extracted the payload adding behavior for events to them
* added SearchErrorResponseAdapter

Signed-off-by: Thomas Jaeckle <thomas.jaeckle@bosch.io>
  • Loading branch information
thjaeckle committed Sep 13, 2021
1 parent 39a9b14 commit 8365d57
Show file tree
Hide file tree
Showing 42 changed files with 985 additions and 685 deletions.
7 changes: 7 additions & 0 deletions protocol/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@
<excludes>
<!-- Don't add excludes here before checking with the whole Ditto team -->
<!--<exclude></exclude>-->
<!-- the following public toAdaptable() methods were not supposed to be public: -->
<exclude>org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter.toAdaptable(org.eclipse.ditto.things.model.signals.commands.query.RetrieveThings,org.eclipse.ditto.protocol.TopicPath$Channel)</exclude>
<exclude>org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter.toAdaptable(org.eclipse.ditto.things.model.signals.commands.query.RetrieveThingsResponse,org.eclipse.ditto.protocol.TopicPath$Channel)</exclude>
<exclude>org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter.toAdaptable(org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand,org.eclipse.ditto.protocol.TopicPath$Channel)</exclude>
<exclude>org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter.toAdaptable(org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent,org.eclipse.ditto.protocol.TopicPath$Channel)</exclude>
<!-- by accident this class was public but must not be: -->
<exclude>org.eclipse.ditto.protocol.adapter.things.ThingSearchCommandAdapter</exclude>
</excludes>
</parameter>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Nullable;

import org.eclipse.ditto.base.model.common.DittoConstants;
import org.eclipse.ditto.base.model.entity.id.NamespacedEntityId;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.base.model.headers.contenttype.ContentType;
import org.eclipse.ditto.connectivity.model.ConnectivityConstants;
import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonPointer;
import org.eclipse.ditto.policies.model.PolicyConstants;
import org.eclipse.ditto.policies.model.PolicyId;
import org.eclipse.ditto.things.model.ThingConstants;
import org.eclipse.ditto.things.model.ThingId;

/**
Expand Down Expand Up @@ -118,7 +119,14 @@ public static TopicPathBuilder newTopicPathBuilder(final ThingId thingId) {
public static TopicPathBuilder newTopicPathBuilder(final NamespacedEntityId entityId) {
checkNotNull(entityId, "entityId");
final TopicPathBuilder result = ImmutableTopicPath.newBuilder(entityId.getNamespace(), entityId.getName());
return result.things();
if (entityId.getEntityType().equals(ThingConstants.ENTITY_TYPE)) {
return result.things();
} else if (entityId.getEntityType().equals(PolicyConstants.ENTITY_TYPE)) {
return result.policies();
} else if (entityId.getEntityType().equals(ConnectivityConstants.ENTITY_TYPE)) {
return result.connections();
}
return result;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,30 @@
*/
package org.eclipse.ditto.protocol.adapter;

import java.util.Collections;
import java.util.Set;

import org.eclipse.ditto.base.model.entity.id.NamespacedEntityId;
import org.eclipse.ditto.base.model.entity.type.EntityType;
import org.eclipse.ditto.base.model.exceptions.DittoRuntimeException;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.base.model.signals.ErrorRegistry;
import org.eclipse.ditto.base.model.signals.commands.CommandResponse;
import org.eclipse.ditto.base.model.signals.commands.ErrorResponse;
import org.eclipse.ditto.connectivity.model.ConnectivityConstants;
import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonMissingFieldException;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonValue;
import org.eclipse.ditto.base.model.exceptions.DittoRuntimeException;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.policies.model.PolicyConstants;
import org.eclipse.ditto.protocol.Adaptable;
import org.eclipse.ditto.protocol.HeaderTranslator;
import org.eclipse.ditto.protocol.Payload;
import org.eclipse.ditto.protocol.ProtocolFactory;
import org.eclipse.ditto.protocol.TopicPath;
import org.eclipse.ditto.protocol.TopicPathBuildable;
import org.eclipse.ditto.protocol.TopicPathBuilder;
import org.eclipse.ditto.base.model.signals.ErrorRegistry;
import org.eclipse.ditto.base.model.signals.commands.CommandResponse;
import org.eclipse.ditto.base.model.signals.commands.ErrorResponse;
import org.eclipse.ditto.things.model.ThingConstants;

/**
* Adapter for mapping a {@link ErrorResponse} to and from an {@link org.eclipse.ditto.protocol.Adaptable}.
Expand Down Expand Up @@ -79,7 +87,7 @@ public T fromAdaptable(final Adaptable adaptable) {
@Override
public Adaptable toAdaptable(final T errorResponse, final TopicPath.Channel channel) {

final TopicPathBuilder topicPathBuilder = getTopicPathBuilder(errorResponse);
final TopicPath topicPath = getTopicPath(errorResponse, channel);

final Payload payload = Payload.newBuilder(errorResponse.getResourcePath())
.withStatus(errorResponse.getHttpStatus())
Expand All @@ -88,33 +96,63 @@ public Adaptable toAdaptable(final T errorResponse, final TopicPath.Channel chan
.orElse(JsonFactory.nullObject())) // only use the error payload
.build();

final TopicPathBuildable topicPathBuildable;
if (channel == TopicPath.Channel.TWIN) {
topicPathBuildable = topicPathBuilder.twin().errors();
} else if (channel == TopicPath.Channel.LIVE) {
topicPathBuildable = topicPathBuilder.live().errors();
} else if (channel == TopicPath.Channel.NONE) {
topicPathBuildable = topicPathBuilder.none().errors();
} else {
throw new IllegalArgumentException("Unknown Channel '" + channel + "'");
}

final DittoHeaders responseHeaders =
ProtocolFactory.newHeadersWithJsonContentType(errorResponse.getDittoHeaders());

return Adaptable.newBuilder(topicPathBuildable.build())
return Adaptable.newBuilder(topicPath)
.withPayload(payload)
.withHeaders(DittoHeaders.of(headerTranslator.toExternalHeaders(responseHeaders)))
.build();
}

@Override
public Set<TopicPath.Action> getActions() {
return Collections.emptySet();
}

@Override
public TopicPath toTopicPath(final T t, final TopicPath.Channel channel) {
return getTopicPath(t, channel);
}

/**
* Implementations must provide a {@link TopicPathBuilder} for the given {@code errorResponse}.
*
* @param errorResponse the processed error response
* @return the {@link TopicPathBuilder} used to processed the given {@code errorResponse}
* @deprecated no longer used as of Ditto 2.1.0,use
* {@link #getTopicPath(org.eclipse.ditto.base.model.signals.commands.ErrorResponse, org.eclipse.ditto.protocol.TopicPath.Channel)} instead
*/
@Deprecated
public TopicPathBuilder getTopicPathBuilder(final T errorResponse) {
final TopicPath topicPath = getTopicPath(errorResponse, TopicPath.Channel.NONE);
final EntityType entityType;
switch (topicPath.getGroup()) {
case THINGS:
entityType = ThingConstants.ENTITY_TYPE;
break;
case POLICIES:
entityType = PolicyConstants.ENTITY_TYPE;
break;
case CONNECTIONS:
entityType = ConnectivityConstants.ENTITY_TYPE;
break;
default:
throw new IllegalArgumentException("Unknown group " + topicPath.getGroup());
}
return ProtocolFactory.newTopicPathBuilder(
NamespacedEntityId.of(entityType, topicPath.getNamespace() + ":" + topicPath.getEntityName()));
}

/**
* Implementations must provide a {@link TopicPath} for the given {@code errorResponse}.
*
* @param errorResponse the processed error response
* @param channel the channel to used for determining the topic path.
* @return the {@link TopicPath} used to processed the given {@code errorResponse}
* @since 2.1.0
*/
public abstract TopicPathBuilder getTopicPathBuilder(final T errorResponse);
public abstract TopicPath getTopicPath(T errorResponse, TopicPath.Channel channel);

/**
* Implementations can build the {@link ErrorResponse} from the given parameters.
Expand All @@ -124,6 +162,21 @@ public Adaptable toAdaptable(final T errorResponse, final TopicPath.Channel chan
* @param dittoHeaders the {@link DittoHeaders} used to build the error response
* @return the built error response
*/
public abstract T buildErrorResponse(final TopicPath topicPath, final DittoRuntimeException exception,
final DittoHeaders dittoHeaders);
public abstract T buildErrorResponse(TopicPath topicPath, DittoRuntimeException exception,
DittoHeaders dittoHeaders);

protected static TopicPathBuildable addChannelToTopicPathBuilder(final TopicPathBuilder topicPathBuilder,
final TopicPath.Channel channel) {
final TopicPathBuildable topicPathBuildable;
if (channel == TopicPath.Channel.TWIN) {
topicPathBuildable = topicPathBuilder.twin().errors();
} else if (channel == TopicPath.Channel.LIVE) {
topicPathBuildable = topicPathBuilder.live().errors();
} else if (channel == TopicPath.Channel.NONE) {
topicPathBuildable = topicPathBuilder.none().errors();
} else {
throw new IllegalArgumentException("Unknown Channel '" + channel + "'");
}
return topicPathBuildable;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import java.util.Collections;
import java.util.Set;

import javax.annotation.Nullable;

import org.eclipse.ditto.base.model.json.Jsonifiable;
import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonPointer;
Expand Down Expand Up @@ -58,13 +56,25 @@ default Adaptable toAdaptable(final T t) {
* Maps the given {@code t} to its corresponding {@code Adaptable}.
*
* @param t the object to map.
* @param channel the channel that was used to send the signal
* @param channel the channel that was used to send the signal.
* @return the mapped adaptable.
* @throws NullPointerException if {@code t} is {@code null}.
* @throws NullPointerException if any argument is {@code null}.
* @throws IllegalArgumentException if {@code channel} is unknown.
*/
Adaptable toAdaptable(T t, TopicPath.Channel channel);

/**
* Maps the given {@code t} to its corresponding {@code TopicPath}.
*
* @param t the object to map.
* @param channel the channel that was used to send the signal.
* @return the mapped topic path.
* @throws NullPointerException if any argument is {@code null}.
* @throws IllegalArgumentException if {@code channel} is unknown.
* @since 2.1.0
*/
TopicPath toTopicPath(T t, TopicPath.Channel channel);

/**
* Retrieve the set of groups supported by this adapter.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,30 @@
*/
package org.eclipse.ditto.protocol.adapter;

import org.eclipse.ditto.protocol.Adaptable;
import org.eclipse.ditto.base.model.signals.Signal;
import org.eclipse.ditto.protocol.Adaptable;
import org.eclipse.ditto.protocol.TopicPath;

/**
* Resolves the matching {@link Adapter} for the given {@link org.eclipse.ditto.protocol.Adaptable}.
*/
interface AdapterResolver {

/**
* Select the correct {@link Adapter} (e.g. things/policy, query/modify/...) for the given
* {@link org.eclipse.ditto.protocol.Adaptable}.
* Select the correct {@link Adapter} (e.g. things/policy, query/modify/...) for the given {@link Adaptable}.
*
* @param adaptable the adaptable that is converted to a {@link Signal}
* @return the appropriate {@link org.eclipse.ditto.protocol.Adaptable} capable of converting the {@link org.eclipse.ditto.protocol.Adaptable} to a {@link Signal}
* @param adaptable the adaptable that is converted to a {@link Signal}.
* @return the appropriate {@link Adaptable} capable of converting the {@link Adaptable} to a {@link Signal}
*/
Adapter<? extends Signal<?>> getAdapter(Adaptable adaptable);

/**
* Select the correct {@link Adapter} (e.g. things/policy, query/modify/...) for the given {@link Signal}.
*
* @param signal the signal that should be converted via the returned {@link Adapter}.
* @param channel the channel to retrieve the adapter for.
* @return the appropriate {@link Adaptable} capable of converting the passed {@link Signal}
* @since 2.1.0
*/
Adapter<Signal<?>> getAdapter(Signal<?> signal, TopicPath.Channel channel);
}

0 comments on commit 8365d57

Please sign in to comment.