diff --git a/protocol/pom.xml b/protocol/pom.xml index 122f54520e..afc3d7a1f2 100755 --- a/protocol/pom.xml +++ b/protocol/pom.xml @@ -185,6 +185,13 @@ + + org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter.toAdaptable(org.eclipse.ditto.things.model.signals.commands.query.RetrieveThings,org.eclipse.ditto.protocol.TopicPath$Channel) + org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter.toAdaptable(org.eclipse.ditto.things.model.signals.commands.query.RetrieveThingsResponse,org.eclipse.ditto.protocol.TopicPath$Channel) + org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter.toAdaptable(org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand,org.eclipse.ditto.protocol.TopicPath$Channel) + org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter.toAdaptable(org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent,org.eclipse.ditto.protocol.TopicPath$Channel) + + org.eclipse.ditto.protocol.adapter.things.ThingSearchCommandAdapter diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/ProtocolFactory.java b/protocol/src/main/java/org/eclipse/ditto/protocol/ProtocolFactory.java index 8dae07de10..b5c4aa60fa 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/ProtocolFactory.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/ProtocolFactory.java @@ -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; /** @@ -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; } /** diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/AbstractErrorResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/AbstractErrorResponseAdapter.java index eb1810388e..7f3720b391 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/AbstractErrorResponseAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/AbstractErrorResponseAdapter.java @@ -12,12 +12,22 @@ */ 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; @@ -25,9 +35,7 @@ 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}. @@ -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()) @@ -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 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. @@ -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; + } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/Adapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/Adapter.java index bc784e2775..db475641ab 100755 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/Adapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/Adapter.java @@ -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; @@ -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. * diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/AdapterResolver.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/AdapterResolver.java index 42651f7017..b306fd02f7 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/AdapterResolver.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/AdapterResolver.java @@ -12,8 +12,9 @@ */ 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}. @@ -21,12 +22,20 @@ 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> 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> getAdapter(Signal signal, TopicPath.Channel channel); } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/DefaultAdapterResolver.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/DefaultAdapterResolver.java index b7bab1e65b..635cafd55a 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/DefaultAdapterResolver.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/DefaultAdapterResolver.java @@ -12,6 +12,10 @@ */ package org.eclipse.ditto.protocol.adapter; +import static org.eclipse.ditto.protocol.TopicPath.Channel.LIVE; +import static org.eclipse.ditto.protocol.TopicPath.Channel.NONE; +import static org.eclipse.ditto.protocol.TopicPath.Channel.TWIN; + import java.util.ArrayList; import java.util.Arrays; import java.util.EnumMap; @@ -24,13 +28,40 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import org.eclipse.ditto.base.model.signals.Signal; +import org.eclipse.ditto.base.model.signals.acks.Acknowledgement; +import org.eclipse.ditto.base.model.signals.acks.Acknowledgements; +import org.eclipse.ditto.connectivity.model.signals.announcements.ConnectivityAnnouncement; +import org.eclipse.ditto.messages.model.signals.commands.MessageCommand; +import org.eclipse.ditto.messages.model.signals.commands.MessageCommandResponse; +import org.eclipse.ditto.policies.model.signals.announcements.PolicyAnnouncement; +import org.eclipse.ditto.policies.model.signals.commands.PolicyErrorResponse; +import org.eclipse.ditto.policies.model.signals.commands.modify.PolicyModifyCommand; +import org.eclipse.ditto.policies.model.signals.commands.modify.PolicyModifyCommandResponse; +import org.eclipse.ditto.policies.model.signals.commands.query.PolicyQueryCommand; +import org.eclipse.ditto.policies.model.signals.commands.query.PolicyQueryCommandResponse; import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.TopicPath; +import org.eclipse.ditto.protocol.UnknownChannelException; +import org.eclipse.ditto.protocol.UnknownSignalException; import org.eclipse.ditto.protocol.adapter.connectivity.ConnectivityCommandAdapterProvider; import org.eclipse.ditto.protocol.adapter.provider.AcknowledgementAdapterProvider; import org.eclipse.ditto.protocol.adapter.provider.PolicyCommandAdapterProvider; import org.eclipse.ditto.protocol.adapter.provider.ThingCommandAdapterProvider; -import org.eclipse.ditto.base.model.signals.Signal; +import org.eclipse.ditto.things.model.signals.commands.ThingErrorResponse; +import org.eclipse.ditto.things.model.signals.commands.modify.MergeThing; +import org.eclipse.ditto.things.model.signals.commands.modify.MergeThingResponse; +import org.eclipse.ditto.things.model.signals.commands.modify.ThingModifyCommand; +import org.eclipse.ditto.things.model.signals.commands.modify.ThingModifyCommandResponse; +import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThings; +import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThingsResponse; +import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommand; +import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommandResponse; +import org.eclipse.ditto.things.model.signals.events.ThingEvent; +import org.eclipse.ditto.things.model.signals.events.ThingMerged; +import org.eclipse.ditto.thingsearch.model.signals.commands.SearchErrorResponse; +import org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand; +import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent; /** * Implements the logic to select the correct {@link org.eclipse.ditto.protocol.adapter.Adapter} from a given {@link org.eclipse.ditto.protocol.Adaptable}. @@ -38,6 +69,7 @@ final class DefaultAdapterResolver implements AdapterResolver { private final Function> resolver; + private final AdapterResolverBySignal resolverBySignal; DefaultAdapterResolver(final ThingCommandAdapterProvider thingsAdapters, final PolicyCommandAdapterProvider policiesAdapters, @@ -49,6 +81,8 @@ final class DefaultAdapterResolver implements AdapterResolver { adapters.addAll(connectivityAdapters.getAdapters()); adapters.addAll(acknowledgementAdapters.getAdapters()); resolver = computeResolver(adapters); + resolverBySignal = new AdapterResolverBySignal(thingsAdapters, policiesAdapters, connectivityAdapters, + acknowledgementAdapters); } @Override @@ -57,6 +91,11 @@ public Adapter> getAdapter(final Adaptable adaptable) { return (Adapter>) resolver.apply(adaptable); } + @Override + public Adapter> getAdapter(final Signal signal, final TopicPath.Channel channel) { + return resolverBySignal.resolve(signal, channel); + } + private static boolean isResponse(final Adaptable adaptable) { return adaptable.getPayload().getHttpStatus().isPresent(); } @@ -268,7 +307,8 @@ private static final class ForEnumOptional> implements Resolve private final Function, Set> getSupportedEnums; private final Function> extractEnum; - private ForEnumOptional(final Class enumClass, final T[] enumValues, + private ForEnumOptional(final Class enumClass, + final T[] enumValues, final Function, Set> getSupportedEnums, final Function> extractEnum) { this.enumClass = enumClass; @@ -430,4 +470,154 @@ private static Function> composeAsSet(final Predicate predic return t -> EnumSet.of(Bool.of(predicate.test(t))); } } + + private static final class AdapterResolverBySignal { + + private final ThingCommandAdapterProvider thingsAdapters; + private final PolicyCommandAdapterProvider policiesAdapters; + private final ConnectivityCommandAdapterProvider connectivityAdapters; + private final AcknowledgementAdapterProvider acknowledgementAdapters; + + private AdapterResolverBySignal(final ThingCommandAdapterProvider thingsAdapters, + final PolicyCommandAdapterProvider policiesAdapters, + final ConnectivityCommandAdapterProvider connectivityAdapters, + final AcknowledgementAdapterProvider acknowledgementAdapters) { + + this.thingsAdapters = thingsAdapters; + this.policiesAdapters = policiesAdapters; + this.connectivityAdapters = connectivityAdapters; + this.acknowledgementAdapters = acknowledgementAdapters; + } + + @SuppressWarnings("unchecked") + public > Adapter resolve(final T signal, final TopicPath.Channel channel) { + if (signal instanceof MessageCommand) { + validateChannel(channel, signal, LIVE); + return (Adapter) thingsAdapters.getMessageCommandAdapter(); + } + if (signal instanceof MessageCommandResponse) { + validateChannel(channel, signal, LIVE); + return (Adapter) thingsAdapters.getMessageCommandResponseAdapter(); + } + if (signal instanceof ThingSearchCommand) { + validateNotLive(signal); + return (Adapter) thingsAdapters.getSearchCommandAdapter(); + } + if (signal instanceof MergeThing) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getMergeCommandAdapter(); + } + if (signal instanceof MergeThingResponse) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getMergeCommandResponseAdapter(); + } + if (signal instanceof ThingModifyCommand) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getModifyCommandAdapter(); + } + if (signal instanceof ThingModifyCommandResponse) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getModifyCommandResponseAdapter(); + } + if (signal instanceof ThingQueryCommand) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getQueryCommandAdapter(); + } + if (signal instanceof ThingQueryCommandResponse) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getQueryCommandResponseAdapter(); + } + if (signal instanceof RetrieveThings) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getRetrieveThingsCommandAdapter(); + } + if (signal instanceof RetrieveThingsResponse) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getRetrieveThingsCommandResponseAdapter(); + } + if (signal instanceof ThingErrorResponse) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getErrorResponseAdapter(); + } + if (signal instanceof ThingMerged) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getMergedEventAdapter(); + } + if (signal instanceof ThingEvent) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) thingsAdapters.getEventAdapter(); + } + if (signal instanceof SubscriptionEvent) { + validateNotLive(signal); + return (Adapter) thingsAdapters.getSubscriptionEventAdapter(); + } + if (signal instanceof SearchErrorResponse) { + validateNotLive(signal); + return (Adapter) thingsAdapters.getSearchErrorResponseAdapter(); + } + + if (signal instanceof PolicyModifyCommand) { + validateChannel(channel, signal, NONE); + return (Adapter) policiesAdapters.getModifyCommandAdapter(); + } + if (signal instanceof PolicyModifyCommandResponse) { + validateChannel(channel, signal, NONE); + return (Adapter) policiesAdapters.getModifyCommandResponseAdapter(); + } + if (signal instanceof PolicyQueryCommand) { + validateChannel(channel, signal, NONE); + return (Adapter) policiesAdapters.getQueryCommandAdapter(); + } + if (signal instanceof PolicyQueryCommandResponse) { + validateChannel(channel, signal, NONE); + return (Adapter) policiesAdapters.getQueryCommandResponseAdapter(); + } + if (signal instanceof PolicyErrorResponse) { + validateChannel(channel, signal, NONE); + return (Adapter) policiesAdapters.getErrorResponseAdapter(); + } + if (signal instanceof PolicyAnnouncement) { + validateChannel(channel, signal, NONE); + return (Adapter) policiesAdapters.getAnnouncementAdapter(); + } + + if (signal instanceof ConnectivityAnnouncement) { + validateChannel(channel, signal, NONE); + return (Adapter) connectivityAdapters.getAnnouncementAdapter(); + } + + if (signal instanceof Acknowledgement) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) acknowledgementAdapters.getAcknowledgementAdapter(); + } + if (signal instanceof Acknowledgements) { + validateChannel(channel, signal, LIVE, TWIN); + return (Adapter) acknowledgementAdapters.getAcknowledgementsAdapter(); + } + + throw UnknownSignalException.newBuilder(signal.getName()) + .dittoHeaders(signal.getDittoHeaders()) + .build(); + } + + private void validateChannel(final TopicPath.Channel channel, + final Signal signal, final TopicPath.Channel... supportedChannels) { + if (!Arrays.asList(supportedChannels).contains(channel)) { + throw unknownChannelException(signal, channel); + } + } + + private void validateNotLive(final Signal signal) { + if (ProtocolAdapter.isLiveSignal(signal)) { + throw unknownChannelException(signal, LIVE); + } + } + + private UnknownChannelException unknownChannelException(final Signal signal, + final TopicPath.Channel channel) { + return UnknownChannelException.newBuilder(channel, signal.getType()) + .dittoHeaders(signal.getDittoHeaders()) + .build(); + } + } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/DittoProtocolAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/DittoProtocolAdapter.java index 3c35d2fb30..ba59a12f7a 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/DittoProtocolAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/DittoProtocolAdapter.java @@ -13,47 +13,17 @@ package org.eclipse.ditto.protocol.adapter; import static org.eclipse.ditto.base.model.common.ConditionChecker.checkNotNull; -import static org.eclipse.ditto.protocol.TopicPath.Channel.LIVE; -import static org.eclipse.ditto.protocol.TopicPath.Channel.NONE; -import static org.eclipse.ditto.protocol.TopicPath.Channel.TWIN; - -import java.util.Arrays; import org.eclipse.ditto.base.model.exceptions.DittoJsonException; import org.eclipse.ditto.base.model.exceptions.DittoRuntimeException; import org.eclipse.ditto.base.model.headers.DittoHeaderDefinition; -import org.eclipse.ditto.base.model.headers.DittoHeaders; import org.eclipse.ditto.base.model.signals.ErrorRegistry; import org.eclipse.ditto.base.model.signals.GlobalErrorRegistry; import org.eclipse.ditto.base.model.signals.Signal; -import org.eclipse.ditto.base.model.signals.acks.Acknowledgement; -import org.eclipse.ditto.base.model.signals.acks.Acknowledgements; -import org.eclipse.ditto.base.model.signals.commands.Command; -import org.eclipse.ditto.base.model.signals.commands.CommandResponse; -import org.eclipse.ditto.base.model.signals.events.Event; -import org.eclipse.ditto.connectivity.model.signals.announcements.ConnectivityAnnouncement; -import org.eclipse.ditto.json.JsonFactory; -import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.messages.model.MessageHeaderDefinition; -import org.eclipse.ditto.messages.model.signals.commands.MessageCommand; -import org.eclipse.ditto.messages.model.signals.commands.MessageCommandResponse; -import org.eclipse.ditto.policies.model.signals.announcements.PolicyAnnouncement; -import org.eclipse.ditto.policies.model.signals.commands.PolicyCommandResponse; -import org.eclipse.ditto.policies.model.signals.commands.PolicyErrorResponse; -import org.eclipse.ditto.policies.model.signals.commands.modify.PolicyModifyCommand; -import org.eclipse.ditto.policies.model.signals.commands.modify.PolicyModifyCommandResponse; -import org.eclipse.ditto.policies.model.signals.commands.query.PolicyQueryCommand; -import org.eclipse.ditto.policies.model.signals.commands.query.PolicyQueryCommandResponse; 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.UnknownChannelException; -import org.eclipse.ditto.protocol.UnknownCommandException; -import org.eclipse.ditto.protocol.UnknownCommandResponseException; -import org.eclipse.ditto.protocol.UnknownEventException; -import org.eclipse.ditto.protocol.UnknownSignalException; import org.eclipse.ditto.protocol.adapter.acknowledgements.DefaultAcknowledgementsAdapterProvider; import org.eclipse.ditto.protocol.adapter.connectivity.ConnectivityCommandAdapterProvider; import org.eclipse.ditto.protocol.adapter.connectivity.DefaultConnectivityCommandAdapterProvider; @@ -62,21 +32,6 @@ import org.eclipse.ditto.protocol.adapter.provider.PolicyCommandAdapterProvider; import org.eclipse.ditto.protocol.adapter.provider.ThingCommandAdapterProvider; import org.eclipse.ditto.protocol.adapter.things.DefaultThingCommandAdapterProvider; -import org.eclipse.ditto.things.model.signals.commands.ThingCommandResponse; -import org.eclipse.ditto.things.model.signals.commands.ThingErrorResponse; -import org.eclipse.ditto.things.model.signals.commands.modify.MergeThing; -import org.eclipse.ditto.things.model.signals.commands.modify.MergeThingResponse; -import org.eclipse.ditto.things.model.signals.commands.modify.ThingModifyCommand; -import org.eclipse.ditto.things.model.signals.commands.modify.ThingModifyCommandResponse; -import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThings; -import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThingsResponse; -import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommand; -import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommandResponse; -import org.eclipse.ditto.things.model.signals.events.ThingEvent; -import org.eclipse.ditto.things.model.signals.events.ThingMerged; -import org.eclipse.ditto.thingsearch.model.signals.commands.SearchErrorResponse; -import org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand; -import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent; /** * Adapter for the Ditto protocol. @@ -102,9 +57,11 @@ private DittoProtocolAdapter(final ErrorRegistry errorReg } private DittoProtocolAdapter(final HeaderTranslator headerTranslator, - final ThingCommandAdapterProvider thingsAdapters, final PolicyCommandAdapterProvider policiesAdapters, + final ThingCommandAdapterProvider thingsAdapters, + final PolicyCommandAdapterProvider policiesAdapters, final ConnectivityCommandAdapterProvider connectivityAdapters, - final AcknowledgementAdapterProvider acknowledgementAdapters, final AdapterResolver adapterResolver) { + final AcknowledgementAdapterProvider acknowledgementAdapters, + final AdapterResolver adapterResolver) { this.headerTranslator = checkNotNull(headerTranslator, "headerTranslator"); this.thingsAdapters = checkNotNull(thingsAdapters, "thingsAdapters"); this.policiesAdapters = checkNotNull(policiesAdapters, "policiesAdapters"); @@ -173,221 +130,12 @@ public Signal fromAdaptable(final Adaptable adaptable) { @Override public Adaptable toAdaptable(final Signal signal) { final TopicPath.Channel channel = ProtocolAdapter.determineChannel(signal); - return toAdaptable(signal, channel); + return adapterResolver.getAdapter(signal, channel).toAdaptable(signal, channel); } @Override public Adaptable toAdaptable(final Signal signal, final TopicPath.Channel channel) { - if (signal instanceof MessageCommand) { - validateChannel(channel, signal, LIVE); - return toAdaptable((MessageCommand) signal); - } else if (signal instanceof MessageCommandResponse) { - validateChannel(channel, signal, LIVE); - return toAdaptable((MessageCommandResponse) signal); - } else if (signal instanceof ThingSearchCommand) { - return toAdaptable((ThingSearchCommand) signal, channel); - } else if (signal instanceof Command) { - return toAdaptable((Command) signal, channel); - } else if (signal instanceof CommandResponse) { - return toAdaptable((CommandResponse) signal, channel); - } else if (signal instanceof Event) { - return toAdaptable((Event) signal, channel); - } else if (signal instanceof PolicyAnnouncement) { - return adaptPolicyAnnouncement((PolicyAnnouncement) signal); - } else if (signal instanceof ConnectivityAnnouncement) { - return adaptConnectivityAnnouncement((ConnectivityAnnouncement) signal); - } - throw UnknownSignalException.newBuilder(signal.getName()).dittoHeaders(signal.getDittoHeaders()).build(); - } - - private Adaptable toAdaptable(final CommandResponse commandResponse, final TopicPath.Channel channel) { - if (commandResponse instanceof MessageCommandResponse) { - validateChannel(channel, commandResponse, LIVE); - return toAdaptable((MessageCommandResponse) commandResponse); - } else if (commandResponse instanceof ThingCommandResponse) { - validateChannel(channel, commandResponse, LIVE, TWIN); - return toAdaptable((ThingCommandResponse) commandResponse, channel); - } else if (commandResponse instanceof RetrieveThingsResponse) { - validateChannel(channel, commandResponse, LIVE, TWIN); - return toAdaptable((RetrieveThingsResponse) commandResponse, channel); - } else if (commandResponse instanceof PolicyCommandResponse) { - validateChannel(channel, commandResponse, NONE); - return toAdaptable((PolicyCommandResponse) commandResponse); - } else if (commandResponse instanceof Acknowledgement) { - validateChannel(channel, commandResponse, LIVE, TWIN); - return toAdaptable((Acknowledgement) commandResponse, channel); - } else if (commandResponse instanceof Acknowledgements) { - validateChannel(channel, commandResponse, LIVE, TWIN); - return toAdaptable((Acknowledgements) commandResponse, channel); - } else if (commandResponse instanceof SearchErrorResponse) { - return toAdaptable((SearchErrorResponse) commandResponse); - } - throw UnknownCommandResponseException.newBuilder(commandResponse.getName()).build(); - } - - private Adaptable toAdaptable(final ThingCommandResponse thingCommandResponse, final TopicPath.Channel channel) { - validateChannel(channel, thingCommandResponse, LIVE, TWIN); - if (thingCommandResponse instanceof ThingQueryCommandResponse) { - return toAdaptable((ThingQueryCommandResponse) thingCommandResponse, channel); - } else if (thingCommandResponse instanceof ThingModifyCommandResponse) { - return toAdaptable((ThingModifyCommandResponse) thingCommandResponse, channel); - } else if (thingCommandResponse instanceof ThingErrorResponse) { - return toAdaptable((ThingErrorResponse) thingCommandResponse, channel); - } - throw UnknownCommandResponseException.newBuilder(thingCommandResponse.getName()).build(); - } - - private Adaptable toAdaptable(final PolicyCommandResponse policyCommandResponse) { - if (policyCommandResponse instanceof PolicyQueryCommandResponse) { - return toAdaptable((PolicyQueryCommandResponse) policyCommandResponse); - } else if (policyCommandResponse instanceof PolicyModifyCommandResponse) { - return toAdaptable((PolicyModifyCommandResponse) policyCommandResponse); - } else if (policyCommandResponse instanceof PolicyErrorResponse) { - return toAdaptable((PolicyErrorResponse) policyCommandResponse); - } - throw UnknownCommandResponseException.newBuilder(policyCommandResponse.getName()).build(); - } - - private Adaptable toAdaptable(final Command command, final TopicPath.Channel channel) { - if (command instanceof MessageCommand) { - validateChannel(channel, command, LIVE); - return toAdaptable((MessageCommand) command); - } else if (command instanceof ThingModifyCommand) { - validateChannel(channel, command, LIVE, TWIN); - return toAdaptable((ThingModifyCommand) command, channel); - } else if (command instanceof ThingSearchCommand) { - return toAdaptable((ThingSearchCommand) command, channel); - } else if (command instanceof ThingQueryCommand) { - validateChannel(channel, command, LIVE, TWIN); - return toAdaptable((ThingQueryCommand) command, channel); - } else if (command instanceof RetrieveThings) { - validateChannel(channel, command, LIVE, TWIN); - return toAdaptable((RetrieveThings) command, channel); - } else if (command instanceof PolicyModifyCommand) { - validateChannel(channel, command, NONE); - return toAdaptable((PolicyModifyCommand) command); - } else if (command instanceof PolicyQueryCommand) { - validateChannel(channel, command, NONE); - return toAdaptable((PolicyQueryCommand) command); - } - throw UnknownCommandException.newBuilder(command.getName()).build(); - } - - private Adaptable toAdaptable(final ThingQueryCommand thingQueryCommand, final TopicPath.Channel channel) { - validateChannel(channel, thingQueryCommand, TWIN, LIVE); - return thingsAdapters.getQueryCommandAdapter().toAdaptable(thingQueryCommand, channel); - } - - public Adaptable toAdaptable(final RetrieveThings retrieveThings, final TopicPath.Channel channel) { - validateChannel(channel, retrieveThings, TWIN, LIVE); - return thingsAdapters.getRetrieveThingsCommandAdapter().toAdaptable(retrieveThings, channel); - } - - public Adaptable toAdaptable(final RetrieveThingsResponse retrieveThingsResponse, final TopicPath.Channel channel) { - validateChannel(channel, retrieveThingsResponse, TWIN, LIVE); - return thingsAdapters.getRetrieveThingsCommandResponseAdapter().toAdaptable(retrieveThingsResponse, channel); - } - - public Adaptable toAdaptable(final ThingSearchCommand thingSearchCommand, final TopicPath.Channel channel) { - validateChannel(channel, thingSearchCommand, TWIN); - return thingsAdapters.getSearchCommandAdapter().toAdaptable(thingSearchCommand, channel); - } - - private Adaptable toAdaptable(final ThingQueryCommandResponse thingQueryCommandResponse, - final TopicPath.Channel channel) { - validateChannel(channel, thingQueryCommandResponse, TWIN, LIVE); - return thingsAdapters.getQueryCommandResponseAdapter().toAdaptable(thingQueryCommandResponse, channel); - } - - private Adaptable toAdaptable(final ThingModifyCommand thingModifyCommand, final TopicPath.Channel channel) { - validateChannel(channel, thingModifyCommand, TWIN, LIVE); - if (thingModifyCommand instanceof MergeThing) { - return thingsAdapters.getMergeCommandAdapter().toAdaptable((MergeThing) thingModifyCommand, channel); - } else { - return thingsAdapters.getModifyCommandAdapter().toAdaptable(thingModifyCommand, channel); - } - } - - private Adaptable toAdaptable(final ThingModifyCommandResponse thingModifyCommandResponse, - final TopicPath.Channel channel) { - validateChannel(channel, thingModifyCommandResponse, TWIN, LIVE); - if (thingModifyCommandResponse instanceof MergeThingResponse) { - return thingsAdapters.getMergeCommandResponseAdapter() - .toAdaptable((MergeThingResponse) thingModifyCommandResponse, channel); - } else { - return thingsAdapters.getModifyCommandResponseAdapter().toAdaptable(thingModifyCommandResponse, channel); - } - } - - private Adaptable toAdaptable(final Event event, final TopicPath.Channel channel) { - if (event instanceof ThingEvent) { - validateChannel(channel, event, TWIN, LIVE); - return toAdaptable((ThingEvent) event, channel); - } else if (event instanceof SubscriptionEvent) { - validateChannel(channel, event, TWIN); - return toAdaptable((SubscriptionEvent) event, channel); - } - throw UnknownEventException.newBuilder(event.getName()).build(); - } - - private Adaptable toAdaptable(final ThingErrorResponse thingErrorResponse, final TopicPath.Channel channel) { - validateChannel(channel, thingErrorResponse, TWIN, LIVE); - return thingsAdapters.getErrorResponseAdapter().toAdaptable(thingErrorResponse, channel); - } - - private Adaptable toAdaptable(final ThingEvent thingEvent, final TopicPath.Channel channel) { - validateChannel(channel, thingEvent, TWIN, LIVE); - if (thingEvent instanceof ThingMerged) { - return thingsAdapters.getMergedEventAdapter().toAdaptable((ThingMerged) thingEvent, channel); - } else { - return thingsAdapters.getEventAdapter().toAdaptable(thingEvent, channel); - } - } - - private Adaptable adaptPolicyAnnouncement(final PolicyAnnouncement announcement) { - return policiesAdapters.getAnnouncementAdapter().toAdaptable(announcement); - } - - private Adaptable adaptConnectivityAnnouncement(final ConnectivityAnnouncement announcement) { - return connectivityAdapters.getAnnouncementAdapter().toAdaptable(announcement); - } - - public Adaptable toAdaptable(final SubscriptionEvent subscriptionEvent, final TopicPath.Channel channel) { - validateNotLive(subscriptionEvent); - return thingsAdapters.getSubscriptionEventAdapter().toAdaptable(subscriptionEvent, channel); - } - - private Adaptable toAdaptable(final PolicyQueryCommand policyQueryCommand) { - validateNotLive(policyQueryCommand); - return policiesAdapters.getQueryCommandAdapter().toAdaptable(policyQueryCommand, NONE); - } - - private Adaptable toAdaptable(final PolicyQueryCommandResponse policyQueryCommandResponse) { - validateNotLive(policyQueryCommandResponse); - return policiesAdapters.getQueryCommandResponseAdapter().toAdaptable(policyQueryCommandResponse, NONE); - } - - private Adaptable toAdaptable(final PolicyModifyCommand policyModifyCommand) { - validateNotLive(policyModifyCommand); - return policiesAdapters.getModifyCommandAdapter().toAdaptable(policyModifyCommand, NONE); - } - - private Adaptable toAdaptable(final PolicyModifyCommandResponse policyModifyCommandResponse) { - validateNotLive(policyModifyCommandResponse); - return policiesAdapters.getModifyCommandResponseAdapter().toAdaptable(policyModifyCommandResponse, NONE); - } - - private Adaptable toAdaptable(final PolicyErrorResponse policyErrorResponse) { - validateNotLive(policyErrorResponse); - return policiesAdapters.getErrorResponseAdapter().toAdaptable(policyErrorResponse, NONE); - } - - private Adaptable toAdaptable(final MessageCommand messageCommand) { - return thingsAdapters.getMessageCommandAdapter().toAdaptable(messageCommand, LIVE); - } - - private Adaptable toAdaptable(final MessageCommandResponse messageCommandResponse) { - return thingsAdapters.getMessageCommandResponseAdapter().toAdaptable(messageCommandResponse, LIVE); + return adapterResolver.getAdapter(signal, channel).toAdaptable(signal, channel); } @Override @@ -395,54 +143,10 @@ public HeaderTranslator headerTranslator() { return headerTranslator; } - private Adaptable toAdaptable(final Acknowledgement acknowledgement, final TopicPath.Channel channel) { - return acknowledgementAdapters.getAcknowledgementAdapter().toAdaptable(acknowledgement, channel); - } - - private Adaptable toAdaptable(final Acknowledgements acknowledgements, final TopicPath.Channel channel) { - return acknowledgementAdapters.getAcknowledgementsAdapter().toAdaptable(acknowledgements, channel); - } - - private Adaptable toAdaptable(final SearchErrorResponse errorResponse) { - final DittoHeaders responseHeaders = - ProtocolFactory.newHeadersWithJsonContentType(errorResponse.getDittoHeaders()); - - final Payload payload = Payload.newBuilder(JsonPointer.empty()) - .withStatus(errorResponse.getHttpStatus()) - .withValue(errorResponse.toJson(errorResponse.getImplementedSchemaVersion()) - .getValue(CommandResponse.JsonFields.PAYLOAD) - .orElse(JsonFactory.nullObject())) // only use the error payload - .build(); - - final TopicPath errorTopicPath = ProtocolFactory.newTopicPathBuilderFromNamespace(TopicPath.ID_PLACEHOLDER) - .things() - .none() - .search() - .error() - .build(); - - return Adaptable.newBuilder(errorTopicPath) - .withPayload(payload) - .withHeaders(DittoHeaders.of(getHeaderTranslator().toExternalHeaders(responseHeaders))) - .build(); - } - - private void validateChannel(final TopicPath.Channel channel, - final Signal signal, final TopicPath.Channel... supportedChannels) { - if (!Arrays.asList(supportedChannels).contains(channel)) { - throw unknownChannelException(signal, channel); - } - } - - private void validateNotLive(final Signal signal) { - if (ProtocolAdapter.isLiveSignal(signal)) { - throw unknownChannelException(signal, LIVE); - } + @Override + public TopicPath toTopicPath(final Signal signal) { + final TopicPath.Channel channel = ProtocolAdapter.determineChannel(signal); + return adapterResolver.getAdapter(signal, channel).toTopicPath(signal, channel); } - private UnknownChannelException unknownChannelException(final Signal signal, final TopicPath.Channel channel) { - return UnknownChannelException.newBuilder(channel, signal.getType()) - .dittoHeaders(signal.getDittoHeaders()) - .build(); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/ProtocolAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/ProtocolAdapter.java index 9cc507530f..12eb8a3da6 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/ProtocolAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/ProtocolAdapter.java @@ -16,14 +16,15 @@ import static org.eclipse.ditto.protocol.TopicPath.Channel.NONE; import static org.eclipse.ditto.protocol.TopicPath.Channel.TWIN; -import org.eclipse.ditto.protocol.Adaptable; -import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.TopicPath; import org.eclipse.ditto.base.model.signals.Signal; +import org.eclipse.ditto.base.model.signals.announcements.Announcement; import org.eclipse.ditto.messages.model.signals.commands.MessageCommand; import org.eclipse.ditto.messages.model.signals.commands.MessageCommandResponse; import org.eclipse.ditto.policies.model.signals.commands.PolicyCommand; import org.eclipse.ditto.policies.model.signals.commands.PolicyCommandResponse; +import org.eclipse.ditto.protocol.Adaptable; +import org.eclipse.ditto.protocol.HeaderTranslator; +import org.eclipse.ditto.protocol.TopicPath; /** * A protocol adapter provides methods for mapping {@link Signal} instances to an {@link org.eclipse.ditto.protocol.Adaptable}. @@ -59,6 +60,15 @@ public interface ProtocolAdapter { */ Adaptable toAdaptable(Signal signal, TopicPath.Channel channel); + /** + * Maps the given {@code Signal} to its {@code TopicPath}. + * + * @param signal the signal. + * @return the topic path. + * @since 2.1.0 + */ + TopicPath toTopicPath(Signal signal); + /** * Retrieve the header translator responsible for this protocol adapter. * @@ -104,10 +114,13 @@ static TopicPath.Channel determineChannel(final Signal signal) { static TopicPath.Channel determineDefaultChannel(final Signal signal) { if (signal instanceof PolicyCommand || signal instanceof PolicyCommandResponse) { return NONE; + } else if (signal instanceof Announcement) { + return NONE; } else if (signal instanceof MessageCommand || signal instanceof MessageCommandResponse) { return LIVE; } else { return TWIN; } } + } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/acknowledgements/AcknowledgementAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/acknowledgements/AcknowledgementAdapter.java index ee4bb3827a..4d55b01fa8 100755 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/acknowledgements/AcknowledgementAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/acknowledgements/AcknowledgementAdapter.java @@ -22,25 +22,25 @@ import javax.annotation.Nullable; -import org.eclipse.ditto.json.JsonMissingFieldException; -import org.eclipse.ditto.json.JsonPointer; -import org.eclipse.ditto.json.JsonValue; import org.eclipse.ditto.base.model.acks.AcknowledgementLabel; import org.eclipse.ditto.base.model.acks.DittoAcknowledgementLabel; import org.eclipse.ditto.base.model.acks.DittoAcknowledgementLabelExternalUseForbiddenException; import org.eclipse.ditto.base.model.common.HttpStatus; import org.eclipse.ditto.base.model.entity.id.EntityId; import org.eclipse.ditto.base.model.headers.DittoHeaders; -import org.eclipse.ditto.things.model.ThingId; +import org.eclipse.ditto.base.model.signals.acks.Acknowledgement; +import org.eclipse.ditto.json.JsonMissingFieldException; +import org.eclipse.ditto.json.JsonPointer; +import org.eclipse.ditto.json.JsonValue; import org.eclipse.ditto.protocol.AcknowledgementTopicPathBuilder; import org.eclipse.ditto.protocol.Adaptable; -import org.eclipse.ditto.protocol.adapter.Adapter; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.Payload; import org.eclipse.ditto.protocol.TopicPath; import org.eclipse.ditto.protocol.TopicPathBuilder; +import org.eclipse.ditto.protocol.adapter.Adapter; import org.eclipse.ditto.protocol.adapter.UnknownTopicPathException; -import org.eclipse.ditto.base.model.signals.acks.Acknowledgement; +import org.eclipse.ditto.things.model.ThingId; import org.eclipse.ditto.things.model.signals.acks.ThingAcknowledgementFactory; /** @@ -127,6 +127,11 @@ public Adaptable toAdaptable(final Acknowledgement acknowledgement, final TopicP .build(); } + @Override + public TopicPath toTopicPath(final Acknowledgement acknowledgement, final TopicPath.Channel channel) { + return getTopicPath(acknowledgement, channel); + } + @Override public Set getGroups() { return EnumSet.of(TopicPath.Group.THINGS); diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/acknowledgements/AcknowledgementsAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/acknowledgements/AcknowledgementsAdapter.java index 797a320540..4f577ae64c 100755 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/acknowledgements/AcknowledgementsAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/acknowledgements/AcknowledgementsAdapter.java @@ -117,6 +117,11 @@ public Adaptable toAdaptable(final Acknowledgements acknowledgements, final Topi .build(); } + @Override + public TopicPath toTopicPath(final Acknowledgements acknowledgements, final TopicPath.Channel channel) { + return getTopicPath(acknowledgements, channel); + } + @Override public Set getGroups() { return EnumSet.of(TopicPath.Group.THINGS); diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/connectivity/AbstractConnectivityAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/connectivity/AbstractConnectivityAdapter.java index c716a1d000..f9cdf3dfae 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/connectivity/AbstractConnectivityAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/connectivity/AbstractConnectivityAdapter.java @@ -54,4 +54,9 @@ public Adaptable toAdaptable(final T t) { return super.toAdaptable(t, TopicPath.Channel.NONE); } + @Override + public TopicPath toTopicPath(final T t, final TopicPath.Channel channel) { + return signalMapper.mapSignalToTopicPath(t, channel); + } + } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/policies/AbstractPolicyAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/policies/AbstractPolicyAdapter.java index 73fc690eba..68336cc6ce 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/policies/AbstractPolicyAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/policies/AbstractPolicyAdapter.java @@ -49,6 +49,11 @@ protected Adaptable mapSignalToAdaptable(final T signal, final TopicPath.Channel return signalMapper.mapSignalToAdaptable(signal, channel); } + @Override + public TopicPath toTopicPath(final T signal, final TopicPath.Channel channel) { + return signalMapper.mapSignalToTopicPath(signal, channel); + } + @Override public Adaptable validateAndPreprocess(final Adaptable adaptable) { final String subjectsPathSegment = "subjects"; diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/policies/PolicyErrorResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/policies/PolicyErrorResponseAdapter.java index 1a1ab323bb..09f46c3c74 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/policies/PolicyErrorResponseAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/policies/PolicyErrorResponseAdapter.java @@ -16,15 +16,14 @@ 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.policies.model.PolicyId; -import org.eclipse.ditto.protocol.adapter.AbstractErrorResponseAdapter; +import org.eclipse.ditto.policies.model.signals.commands.PolicyErrorResponse; import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.ProtocolFactory; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.TopicPathBuilder; -import org.eclipse.ditto.base.model.signals.ErrorRegistry; -import org.eclipse.ditto.policies.model.signals.commands.PolicyErrorResponse; +import org.eclipse.ditto.protocol.adapter.AbstractErrorResponseAdapter; /** * Adapter for mapping a {@link PolicyErrorResponse} to and from an {@link Adaptable}. @@ -50,8 +49,10 @@ public static PolicyErrorResponseAdapter of(final HeaderTranslator headerTransla } @Override - public TopicPathBuilder getTopicPathBuilder(final PolicyErrorResponse errorResponse) { - return ProtocolFactory.newTopicPathBuilder(errorResponse.getEntityId()); + public TopicPath getTopicPath(final PolicyErrorResponse errorResponse, + final TopicPath.Channel channel) { + return addChannelToTopicPathBuilder(ProtocolFactory.newTopicPathBuilder(errorResponse.getEntityId()), channel) + .build(); } @Override diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/provider/SearchErrorResponseAdapterProvider.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/provider/SearchErrorResponseAdapterProvider.java new file mode 100644 index 0000000000..01ea81bdc6 --- /dev/null +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/provider/SearchErrorResponseAdapterProvider.java @@ -0,0 +1,28 @@ +/* + * 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.protocol.adapter.provider; + +import org.eclipse.ditto.protocol.adapter.Adapter; +import org.eclipse.ditto.thingsearch.model.signals.commands.SearchErrorResponse; + +/** + * Interface providing the search error response adapter. + * @since 2.1.0 + */ +interface SearchErrorResponseAdapterProvider { + + /** + * @return the error response adapter + */ + Adapter getSearchErrorResponseAdapter(); +} diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/provider/ThingCommandAdapterProvider.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/provider/ThingCommandAdapterProvider.java index 4d8afc3ce0..e8266a94ad 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/provider/ThingCommandAdapterProvider.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/provider/ThingCommandAdapterProvider.java @@ -19,8 +19,8 @@ import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThingsResponse; import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommand; import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommandResponse; -import org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand; import org.eclipse.ditto.things.model.signals.events.ThingEvent; +import org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand; import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent; /** @@ -33,6 +33,7 @@ public interface ThingCommandAdapterProvider MergeCommandAdapterProvider, MessageCommandAdapterProvider, ErrorResponseAdapterProvider, + SearchErrorResponseAdapterProvider, EventAdapterProvider>, MergeEventAdapterProvider, SubscriptionEventAdapterProvider>, diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/AbstractMessageAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/AbstractMessageAdapter.java index 11aadc7e92..fc5ad07aae 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/AbstractMessageAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/AbstractMessageAdapter.java @@ -17,17 +17,39 @@ import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.MessagePath; import org.eclipse.ditto.protocol.PayloadPathMatcher; +import org.eclipse.ditto.protocol.TopicPath; import org.eclipse.ditto.protocol.adapter.AbstractAdapter; +import org.eclipse.ditto.protocol.mapper.SignalMapper; import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategies; abstract class AbstractMessageAdapter> extends AbstractAdapter implements ThingMessageAdapter { + private final SignalMapper signalMapper; + AbstractMessageAdapter( final MappingStrategies mappingStrategies, + final SignalMapper signalMapper, final HeaderTranslator headerTranslator, final PayloadPathMatcher payloadPathMatcher) { + super(mappingStrategies, headerTranslator, payloadPathMatcher); + this.signalMapper = signalMapper; + } + + @Override + protected Adaptable mapSignalToAdaptable(final T signal, final TopicPath.Channel channel) { + return signalMapper.mapSignalToAdaptable(signal, channel); + } + + @Override + public Adaptable toAdaptable(final T t) { + return toAdaptable(t, TopicPath.Channel.LIVE); + } + + @Override + public TopicPath toTopicPath(final T signal, final TopicPath.Channel channel) { + return signalMapper.mapSignalToTopicPath(signal, channel); } @Override diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/AbstractThingAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/AbstractThingAdapter.java index 3e4a4375cc..f1d8ae223a 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/AbstractThingAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/AbstractThingAdapter.java @@ -12,20 +12,14 @@ */ package org.eclipse.ditto.protocol.adapter.things; -import java.util.Locale; - import org.eclipse.ditto.base.model.signals.Signal; -import org.eclipse.ditto.protocol.EventsTopicPathBuilder; +import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.PayloadPathMatcher; -import org.eclipse.ditto.protocol.ProtocolFactory; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.TopicPathBuilder; -import org.eclipse.ditto.protocol.UnknownChannelException; -import org.eclipse.ditto.protocol.UnknownEventException; import org.eclipse.ditto.protocol.adapter.AbstractAdapter; +import org.eclipse.ditto.protocol.mapper.SignalMapper; import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategies; -import org.eclipse.ditto.things.model.signals.events.ThingEvent; /** * Base class for {@link org.eclipse.ditto.protocol.adapter.Adapter}s that handle thing commands. @@ -34,17 +28,22 @@ */ abstract class AbstractThingAdapter> extends AbstractAdapter implements ThingAdapter { + private final SignalMapper signalMapper; + /** * Constructor. * * @param mappingStrategies the mapping strategies used to convert from * {@link org.eclipse.ditto.protocol.Adaptable}s to {@link org.eclipse.ditto.base.model.signals.Signal}s + * @param signalMapper the {@link SignalMapper} used to convert from a + * {@link org.eclipse.ditto.base.model.signals.Signal} to an {@link Adaptable} * @param headerTranslator the header translator used for the mapping */ protected AbstractThingAdapter(final MappingStrategies mappingStrategies, + final SignalMapper signalMapper, final HeaderTranslator headerTranslator) { - this(mappingStrategies, headerTranslator, ThingModifyPathMatcher.getInstance()); + this(mappingStrategies, signalMapper, headerTranslator, ThingModifyPathMatcher.getInstance()); } /** @@ -52,59 +51,27 @@ protected AbstractThingAdapter(final MappingStrategies mappingStrategies, * * @param mappingStrategies the mapping strategies used to convert from * {@link org.eclipse.ditto.protocol.Adaptable}s to {@link org.eclipse.ditto.base.model.signals.Signal}s + * @param signalMapper the signal mapper to use for mapping signals to adaptables and to topic paths. * @param headerTranslator the header translator used for the mapping * @param pathMatcher the path matcher used for the mapping */ protected AbstractThingAdapter(final MappingStrategies mappingStrategies, + final SignalMapper signalMapper, final HeaderTranslator headerTranslator, final PayloadPathMatcher pathMatcher) { super(mappingStrategies, headerTranslator, pathMatcher); + this.signalMapper = signalMapper; } - protected static EventsTopicPathBuilder getEventTopicPathBuilderFor(final ThingEvent event, - final TopicPath.Channel channel) { - - final EventsTopicPathBuilder topicPathBuilder = getEventsTopicPathBuilderOrThrow(event, channel); - final String eventName = getLowerCaseEventName(event); - if (isAction(eventName, TopicPath.Action.CREATED)) { - topicPathBuilder.created(); - } else if (isAction(eventName, TopicPath.Action.MODIFIED)) { - topicPathBuilder.modified(); - } else if (isAction(eventName, TopicPath.Action.DELETED)) { - topicPathBuilder.deleted(); - } else if (isAction(eventName, TopicPath.Action.MERGED)) { - topicPathBuilder.merged(); - } else { - throw UnknownEventException.newBuilder(eventName).build(); - } - return topicPathBuilder; - } - - private static EventsTopicPathBuilder getEventsTopicPathBuilderOrThrow(final ThingEvent event, - final TopicPath.Channel channel) { - - TopicPathBuilder topicPathBuilder = ProtocolFactory.newTopicPathBuilder(event.getEntityId()); - if (TopicPath.Channel.TWIN == channel) { - topicPathBuilder = topicPathBuilder.twin(); - } else if (TopicPath.Channel.LIVE == channel) { - topicPathBuilder = topicPathBuilder.live(); - } else { - throw UnknownChannelException.newBuilder(channel, event.getType()) - .dittoHeaders(event.getDittoHeaders()) - .build(); - } - return topicPathBuilder.events(); - } - - private static String getLowerCaseEventName(final ThingEvent thingEvent) { - final Class thingEventClass = thingEvent.getClass(); - final String eventClassSimpleName = thingEventClass.getSimpleName(); - return eventClassSimpleName.toLowerCase(Locale.ENGLISH); + @Override + protected Adaptable mapSignalToAdaptable(final T signal, final TopicPath.Channel channel) { + return signalMapper.mapSignalToAdaptable(signal, channel); } - private static boolean isAction(final String eventName, final TopicPath.Action expectedAction) { - return eventName.contains(expectedAction.getName()); + @Override + public TopicPath toTopicPath(final T signal, final TopicPath.Channel channel) { + return signalMapper.mapSignalToTopicPath(signal, channel); } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/DefaultThingCommandAdapterProvider.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/DefaultThingCommandAdapterProvider.java index d9995b93aa..6c09edb59e 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/DefaultThingCommandAdapterProvider.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/DefaultThingCommandAdapterProvider.java @@ -16,12 +16,12 @@ import java.util.List; import org.eclipse.ditto.base.model.exceptions.DittoRuntimeException; -import org.eclipse.ditto.protocol.adapter.Adapter; -import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.adapter.provider.ThingCommandAdapterProvider; import org.eclipse.ditto.base.model.signals.ErrorRegistry; import org.eclipse.ditto.messages.model.signals.commands.MessageCommand; import org.eclipse.ditto.messages.model.signals.commands.MessageCommandResponse; +import org.eclipse.ditto.protocol.HeaderTranslator; +import org.eclipse.ditto.protocol.adapter.Adapter; +import org.eclipse.ditto.protocol.adapter.provider.ThingCommandAdapterProvider; import org.eclipse.ditto.things.model.signals.commands.ThingErrorResponse; import org.eclipse.ditto.things.model.signals.commands.modify.MergeThing; import org.eclipse.ditto.things.model.signals.commands.modify.MergeThingResponse; @@ -31,9 +31,10 @@ import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThingsResponse; import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommand; import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommandResponse; -import org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand; import org.eclipse.ditto.things.model.signals.events.ThingEvent; import org.eclipse.ditto.things.model.signals.events.ThingMerged; +import org.eclipse.ditto.thingsearch.model.signals.commands.SearchErrorResponse; +import org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand; import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent; @@ -57,6 +58,7 @@ public class DefaultThingCommandAdapterProvider implements ThingCommandAdapterPr private final ThingErrorResponseAdapter errorResponseAdapter; private final RetrieveThingsCommandAdapter retrieveThingsCommandAdapter; private final RetrieveThingsCommandResponseAdapter retrieveThingsCommandResponseAdapter; + private final SearchErrorResponseAdapter searchErrorResponseAdapter; public DefaultThingCommandAdapterProvider(final ErrorRegistry errorRegistry, final HeaderTranslator headerTranslator) { @@ -75,6 +77,7 @@ public DefaultThingCommandAdapterProvider(final ErrorRegistry> getAdapters() { thingMergedEventAdapter, searchCommandAdapter, subscriptionEventAdapter, - errorResponseAdapter + errorResponseAdapter, + searchErrorResponseAdapter ); } @@ -172,4 +176,9 @@ public Adapter getRetrieveThingsCommandAdapter() { public Adapter getRetrieveThingsCommandResponseAdapter() { return retrieveThingsCommandResponseAdapter; } + + @Override + public Adapter getSearchErrorResponseAdapter() { + return searchErrorResponseAdapter; + } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/MessageCommandAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/MessageCommandAdapter.java index d98703970f..af826b03e7 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/MessageCommandAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/MessageCommandAdapter.java @@ -15,29 +15,25 @@ import static java.util.Objects.requireNonNull; import org.eclipse.ditto.messages.model.KnownMessageSubjects; -import org.eclipse.ditto.protocol.adapter.AbstractAdapter; -import org.eclipse.ditto.protocol.Adaptable; -import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.adapter.EmptyPathMatcher; -import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.protocol.mapper.SignalMapper; -import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; import org.eclipse.ditto.messages.model.signals.commands.MessageCommand; import org.eclipse.ditto.messages.model.signals.commands.SendClaimMessage; import org.eclipse.ditto.messages.model.signals.commands.SendFeatureMessage; import org.eclipse.ditto.messages.model.signals.commands.SendThingMessage; +import org.eclipse.ditto.protocol.Adaptable; +import org.eclipse.ditto.protocol.HeaderTranslator; +import org.eclipse.ditto.protocol.adapter.EmptyPathMatcher; +import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; +import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; /** * Adapter for mapping a {@link MessageCommandAdapter} to and from an {@link Adaptable}. */ final class MessageCommandAdapter extends AbstractMessageAdapter> { - private static final SignalMapper> - TO_ADAPTABLE_MAPPER = SignalMapperFactory.newMessageCommandSignalMapper(); - private MessageCommandAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getMessageCommandMappingStrategies(), headerTranslator, + super(MappingStrategiesFactory.getMessageCommandMappingStrategies(), + SignalMapperFactory.newMessageCommandSignalMapper(), + headerTranslator, EmptyPathMatcher.getInstance()); } @@ -51,11 +47,6 @@ public static MessageCommandAdapter of(final HeaderTranslator headerTranslator) return new MessageCommandAdapter(requireNonNull(headerTranslator)); } - @Override - public Adaptable toAdaptable(final MessageCommand t) { - return toAdaptable(t, TopicPath.Channel.LIVE); - } - @Override public boolean isForResponses() { return false; @@ -77,9 +68,4 @@ protected String getType(final Adaptable adaptable) { } } - @Override - public Adaptable mapSignalToAdaptable(final MessageCommand command, final TopicPath.Channel channel) { - return TO_ADAPTABLE_MAPPER.mapSignalToAdaptable(command, channel); - } - } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/MessageCommandResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/MessageCommandResponseAdapter.java index 743a7a769c..6c0fe2db2b 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/MessageCommandResponseAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/MessageCommandResponseAdapter.java @@ -21,9 +21,7 @@ import org.eclipse.ditto.messages.model.signals.commands.SendThingMessageResponse; import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.TopicPath; import org.eclipse.ditto.protocol.adapter.EmptyPathMatcher; -import org.eclipse.ditto.protocol.mapper.SignalMapper; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; @@ -32,11 +30,10 @@ */ final class MessageCommandResponseAdapter extends AbstractMessageAdapter> { - private static final SignalMapper> - TO_ADAPTABLE_MAPPER = SignalMapperFactory.newMessageCommandResponseSignalMapper(); - private MessageCommandResponseAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getMessageCommandResponseMappingStrategies(), headerTranslator, + super(MappingStrategiesFactory.getMessageCommandResponseMappingStrategies(), + SignalMapperFactory.newMessageCommandResponseSignalMapper(), + headerTranslator, EmptyPathMatcher.getInstance()); } @@ -50,11 +47,6 @@ public static MessageCommandResponseAdapter of(final HeaderTranslator headerTran return new MessageCommandResponseAdapter(requireNonNull(headerTranslator)); } - @Override - public Adaptable toAdaptable(final MessageCommandResponse t) { - return toAdaptable(t, TopicPath.Channel.LIVE); - } - @Override public boolean isForResponses() { return true; @@ -76,8 +68,4 @@ protected String getType(final Adaptable adaptable) { } } - @Override - public Adaptable mapSignalToAdaptable(final MessageCommandResponse command, final TopicPath.Channel channel) { - return TO_ADAPTABLE_MAPPER.mapSignalToAdaptable(command, channel); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/RetrieveThingsCommandAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/RetrieveThingsCommandAdapter.java index 1614aeee8f..b7d61718fb 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/RetrieveThingsCommandAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/RetrieveThingsCommandAdapter.java @@ -17,20 +17,17 @@ import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.adapter.QueryCommandAdapter; - import org.eclipse.ditto.protocol.TopicPath; - import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; - import org.eclipse.ditto.protocol.mapper.SignalMapper; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; + import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThings; public final class RetrieveThingsCommandAdapter extends AbstractThingAdapter implements QueryCommandAdapter { - private final SignalMapper retrieveThingsSignalMapper = - SignalMapperFactory.newRetrieveThingsSignalMapper(); - private RetrieveThingsCommandAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getRetrieveThingsCommandMappingStrategies(), headerTranslator); + super(MappingStrategiesFactory.getRetrieveThingsCommandMappingStrategies(), + SignalMapperFactory.newRetrieveThingsSignalMapper(), + headerTranslator); } /** @@ -53,8 +50,4 @@ protected String getType(final Adaptable adaptable) { return RetrieveThings.TYPE; } - @Override - protected Adaptable mapSignalToAdaptable(final RetrieveThings command, final TopicPath.Channel channel) { - return retrieveThingsSignalMapper.mapSignalToAdaptable(command, channel); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/RetrieveThingsCommandResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/RetrieveThingsCommandResponseAdapter.java index b25a2699ba..a8c12589e5 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/RetrieveThingsCommandResponseAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/RetrieveThingsCommandResponseAdapter.java @@ -16,21 +16,19 @@ import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; - import org.eclipse.ditto.protocol.adapter.QueryCommandResponseAdapter; import org.eclipse.ditto.protocol.TopicPath; - import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; - import org.eclipse.ditto.protocol.mapper.SignalMapper; + import org.eclipse.ditto.protocol.adapter.QueryCommandResponseAdapter; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; + import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThingsResponse; public final class RetrieveThingsCommandResponseAdapter extends AbstractThingAdapter implements QueryCommandResponseAdapter { - private final SignalMapper retrieveThingsSignalMapper = - SignalMapperFactory.newRetrieveThingsResponseSignalMapper(); - private RetrieveThingsCommandResponseAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getRetrieveThingsCommandResponseMappingStrategies(), headerTranslator); + super(MappingStrategiesFactory.getRetrieveThingsCommandResponseMappingStrategies(), + SignalMapperFactory.newRetrieveThingsResponseSignalMapper(), + headerTranslator); } /** @@ -58,8 +56,4 @@ protected String getTypeCriterionAsString(final TopicPath topicPath) { return RESPONSES_CRITERION; } - @Override - protected Adaptable mapSignalToAdaptable(final RetrieveThingsResponse command, final TopicPath.Channel channel) { - return retrieveThingsSignalMapper.mapSignalToAdaptable(command, channel); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/SearchErrorResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/SearchErrorResponseAdapter.java new file mode 100644 index 0000000000..ba4c93b09e --- /dev/null +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/SearchErrorResponseAdapter.java @@ -0,0 +1,78 @@ +/* + * 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.protocol.adapter.things; + +import static java.util.Objects.requireNonNull; + +import java.util.EnumSet; +import java.util.Set; + +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.protocol.HeaderTranslator; +import org.eclipse.ditto.protocol.ProtocolFactory; +import org.eclipse.ditto.protocol.TopicPath; +import org.eclipse.ditto.protocol.adapter.AbstractErrorResponseAdapter; +import org.eclipse.ditto.thingsearch.model.signals.commands.SearchErrorResponse; + +/** + * Adapter for mapping a {@link SearchErrorResponse} to and from an {@link org.eclipse.ditto.protocol.Adaptable}. + */ +final class SearchErrorResponseAdapter extends AbstractErrorResponseAdapter + implements ThingAdapter { + + private SearchErrorResponseAdapter(final HeaderTranslator headerTranslator, + final ErrorRegistry errorRegistry) { + super(headerTranslator, errorRegistry); + } + + /** + * Returns a new SearchErrorResponseAdapter. + * + * @param headerTranslator translator between external and Ditto headers. + * @param errorRegistry the {@link org.eclipse.ditto.base.model.signals.ErrorRegistry} used for the mapping + * @return the adapter. + */ + public static SearchErrorResponseAdapter of(final HeaderTranslator headerTranslator, + final ErrorRegistry errorRegistry) { + return new SearchErrorResponseAdapter(requireNonNull(headerTranslator), errorRegistry); + } + + @Override + public TopicPath getTopicPath(final SearchErrorResponse errorResponse, + final TopicPath.Channel channel) { + return ProtocolFactory.newTopicPathBuilderFromNamespace(TopicPath.ID_PLACEHOLDER) + .things() + .none() + .search() + .error() + .build(); + } + + @Override + public boolean supportsWildcardTopics() { + return true; + } + + @Override + public Set getSearchActions() { + return EnumSet.of(TopicPath.SearchAction.ERROR); + } + + @Override + public SearchErrorResponse buildErrorResponse(final TopicPath topicPath, final DittoRuntimeException exception, + final DittoHeaders dittoHeaders) { + return SearchErrorResponse.of(exception, dittoHeaders); + } +} diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/SubscriptionEventAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/SubscriptionEventAdapter.java index 2c88bb7a01..6214bb17b6 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/SubscriptionEventAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/SubscriptionEventAdapter.java @@ -12,39 +12,30 @@ */ package org.eclipse.ditto.protocol.adapter.things; -import static java.util.Objects.requireNonNull; import static org.eclipse.ditto.base.model.common.ConditionChecker.checkNotNull; import java.util.Collections; import java.util.EnumSet; import java.util.Set; -import org.eclipse.ditto.json.JsonFactory; -import org.eclipse.ditto.json.JsonFieldDefinition; -import org.eclipse.ditto.json.JsonObjectBuilder; +import org.eclipse.ditto.base.model.signals.ErrorRegistry; import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.Payload; -import org.eclipse.ditto.protocol.PayloadBuilder; -import org.eclipse.ditto.protocol.ProtocolFactory; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.UnknownEventException; +import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.base.model.signals.ErrorRegistry; -import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionComplete; -import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionCreated; import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent; -import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionFailed; -import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionHasNextPage; /** - * Adapter for mapping a {@link org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent} to and from an {@link Adaptable}. + * Adapter for mapping a {@link SubscriptionEvent} to and from an {@link Adaptable}. */ final class SubscriptionEventAdapter extends AbstractThingAdapter> { private SubscriptionEventAdapter(final HeaderTranslator headerTranslator, final ErrorRegistry errorRegistry) { - super(MappingStrategiesFactory.getSubscriptionEventMappingStrategies(errorRegistry), headerTranslator); + super(MappingStrategiesFactory.getSubscriptionEventMappingStrategies(errorRegistry), + SignalMapperFactory.newSubscriptionEventSignalMapper(), + headerTranslator); } /** @@ -67,47 +58,6 @@ protected String getType(final Adaptable adaptable) { return SubscriptionEvent.TYPE_PREFIX + adaptable.getTopicPath().getSearchAction().orElse(null); } - @Override - protected Adaptable mapSignalToAdaptable(final SubscriptionEvent event, final TopicPath.Channel channel) { - TopicPath topicPath; - final PayloadBuilder payloadBuilder = Payload.newBuilder(event.getResourcePath()); - final JsonObjectBuilder payloadContentBuilder = JsonFactory.newObjectBuilder(); - final JsonFieldDefinition subscriptionIdKey = SubscriptionEvent.JsonFields.SUBSCRIPTION_ID; - - if (event instanceof SubscriptionCreated) { - topicPath = TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().twin().search().generated().build(); - SubscriptionCreated createdEvent = (SubscriptionCreated) event; - payloadContentBuilder.set(subscriptionIdKey, createdEvent.getSubscriptionId()); - - } else if (event instanceof SubscriptionComplete) { - topicPath = TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().twin().search().complete().build(); - SubscriptionComplete completedEvent = (SubscriptionComplete) event; - payloadContentBuilder.set(subscriptionIdKey, completedEvent.getSubscriptionId()); - - } else if (event instanceof SubscriptionFailed) { - topicPath = TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().twin().search().failed().build(); - SubscriptionFailed failedEvent = (SubscriptionFailed) event; - payloadContentBuilder - .set(subscriptionIdKey, failedEvent.getSubscriptionId()) - .set(SubscriptionFailed.JsonFields.ERROR, failedEvent.getError().toJson()); - - } else if (event instanceof SubscriptionHasNextPage) { - topicPath = TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().twin().search().hasNext().build(); - SubscriptionHasNextPage hasNextEvent = (SubscriptionHasNextPage) event; - payloadContentBuilder - .set(subscriptionIdKey, hasNextEvent.getSubscriptionId()) - .set(SubscriptionHasNextPage.JsonFields.ITEMS, hasNextEvent.getItems()); - - } else { - throw UnknownEventException.newBuilder(event.getClass().getCanonicalName()).build(); - } - - return Adaptable.newBuilder(topicPath) - .withPayload(payloadBuilder.withValue(payloadContentBuilder.build()).build()) - .withHeaders(ProtocolFactory.newHeadersWithJsonContentType(event.getDittoHeaders())) - .build(); - } - @Override public Set getCriteria() { return EnumSet.of(TopicPath.Criterion.SEARCH); diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingErrorResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingErrorResponseAdapter.java index 778d03cc0c..8a90e2418b 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingErrorResponseAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingErrorResponseAdapter.java @@ -16,14 +16,13 @@ import org.eclipse.ditto.base.model.exceptions.DittoRuntimeException; import org.eclipse.ditto.base.model.headers.DittoHeaders; -import org.eclipse.ditto.things.model.ThingId; -import org.eclipse.ditto.protocol.adapter.AbstractErrorResponseAdapter; +import org.eclipse.ditto.base.model.signals.ErrorRegistry; import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.ProtocolFactory; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.TopicPathBuilder; -import org.eclipse.ditto.base.model.signals.ErrorRegistry; +import org.eclipse.ditto.protocol.adapter.AbstractErrorResponseAdapter; +import org.eclipse.ditto.things.model.ThingId; import org.eclipse.ditto.things.model.signals.commands.ThingErrorResponse; /** @@ -50,13 +49,15 @@ public static ThingErrorResponseAdapter of(final HeaderTranslator headerTranslat } @Override - public TopicPathBuilder getTopicPathBuilder(final ThingErrorResponse errorResponse) { - return ProtocolFactory.newTopicPathBuilder(errorResponse.getEntityId()); + public TopicPath getTopicPath(final ThingErrorResponse errorResponse, final TopicPath.Channel channel) { + return addChannelToTopicPathBuilder(ProtocolFactory.newTopicPathBuilder(errorResponse.getEntityId()), channel) + .build(); } @Override public ThingErrorResponse buildErrorResponse(final TopicPath topicPath, final DittoRuntimeException exception, final DittoHeaders dittoHeaders) { - return ThingErrorResponse.of(ThingId.of(topicPath.getNamespace(), topicPath.getEntityName()), exception, dittoHeaders); + return ThingErrorResponse.of(ThingId.of(topicPath.getNamespace(), topicPath.getEntityName()), exception, + dittoHeaders); } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingEventAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingEventAdapter.java index 4ef1d7cda4..308bb44ea5 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingEventAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingEventAdapter.java @@ -14,20 +14,13 @@ import static java.util.Objects.requireNonNull; -import java.util.Optional; - import org.eclipse.ditto.json.JsonPointer; -import org.eclipse.ditto.json.JsonValue; -import org.eclipse.ditto.base.model.headers.DittoHeaders; -import org.eclipse.ditto.protocol.adapter.AbstractAdapter; import org.eclipse.ditto.protocol.Adaptable; -import org.eclipse.ditto.protocol.adapter.EventAdapter; -import org.eclipse.ditto.protocol.EventsTopicPathBuilder; import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.Payload; -import org.eclipse.ditto.protocol.PayloadBuilder; -import org.eclipse.ditto.protocol.ProtocolFactory; import org.eclipse.ditto.protocol.TopicPath; +import org.eclipse.ditto.protocol.adapter.AbstractAdapter; +import org.eclipse.ditto.protocol.adapter.EventAdapter; +import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.events.ThingEvent; @@ -37,7 +30,9 @@ final class ThingEventAdapter extends AbstractThingAdapter> implements EventAdapter> { private ThingEventAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingEventMappingStrategies(), headerTranslator); + super(MappingStrategiesFactory.getThingEventMappingStrategies(), + SignalMapperFactory.newThingEventSignalMapper(), + headerTranslator); } /** @@ -65,28 +60,4 @@ protected String getType(final Adaptable adaptable) { return topicPath.getGroup() + "." + topicPath.getCriterion() + ":" + eventName; } - @Override - public Adaptable mapSignalToAdaptable(final ThingEvent event, final TopicPath.Channel channel) { - final EventsTopicPathBuilder eventsTopicPathBuilder = getEventTopicPathBuilderFor(event, channel); - final PayloadBuilder payloadBuilder = Payload.newBuilder(event.getResourcePath()) - .withRevision(event.getRevision()); - event.getTimestamp().ifPresent(payloadBuilder::withTimestamp); - - final Optional value = - event.getEntity(event.getDittoHeaders().getSchemaVersion().orElse(event.getLatestSchemaVersion())); - value.ifPresent(payloadBuilder::withValue); - - final DittoHeaders headers; - if (value.isPresent()) { - headers = ProtocolFactory.newHeadersWithJsonContentType(event.getDittoHeaders()); - } else { - headers = event.getDittoHeaders(); - } - - return Adaptable.newBuilder(eventsTopicPathBuilder.build()) - .withPayload(payloadBuilder.build()) - .withHeaders(headers) - .build(); - } - } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergeCommandAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergeCommandAdapter.java index 65718eba6e..a92b95e5a9 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergeCommandAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergeCommandAdapter.java @@ -18,10 +18,8 @@ import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.adapter.MergeCommandAdapter; -import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.protocol.mapper.SignalMapper; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; +import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.commands.modify.MergeThing; /** @@ -29,10 +27,10 @@ */ final class ThingMergeCommandAdapter extends AbstractThingAdapter implements MergeCommandAdapter { - private final SignalMapper signalMapper = SignalMapperFactory.newThingMergeSignalMapper(); - private ThingMergeCommandAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingMergeCommandMappingStrategies(), headerTranslator, + super(MappingStrategiesFactory.getThingMergeCommandMappingStrategies(), + SignalMapperFactory.newThingMergeSignalMapper(), + headerTranslator, ThingMergePathMatcher.getInstance()); } @@ -52,8 +50,4 @@ protected String getType(final Adaptable adaptable) { return payloadPathMatcher.match(path); } - @Override - public Adaptable mapSignalToAdaptable(final MergeThing command, final TopicPath.Channel channel) { - return signalMapper.mapSignalToAdaptable(command, channel); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergeCommandResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergeCommandResponseAdapter.java index 10b4c0ad2a..e5aa2065ba 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergeCommandResponseAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergeCommandResponseAdapter.java @@ -17,11 +17,10 @@ import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.adapter.MergeCommandResponseAdapter; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.protocol.mapper.SignalMapper; +import org.eclipse.ditto.protocol.adapter.MergeCommandResponseAdapter; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; +import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.commands.modify.MergeThingResponse; /** @@ -31,11 +30,10 @@ final class ThingMergeCommandResponseAdapter extends AbstractThingAdapter implements MergeCommandResponseAdapter { - private final SignalMapper - signalMapper = SignalMapperFactory.newThingMergeResponseSignalMapper(); - private ThingMergeCommandResponseAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingMergeCommandResponseMappingStrategies(), headerTranslator, + super(MappingStrategiesFactory.getThingMergeCommandResponseMappingStrategies(), + SignalMapperFactory.newThingMergeResponseSignalMapper(), + headerTranslator, ThingMergePathMatcher.getInstance()); } @@ -60,8 +58,4 @@ protected String getTypeCriterionAsString(final TopicPath topicPath) { return RESPONSES_CRITERION; } - @Override - protected Adaptable mapSignalToAdaptable(final MergeThingResponse signal, final TopicPath.Channel channel) { - return signalMapper.mapSignalToAdaptable(signal, channel); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergedEventAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergedEventAdapter.java index 5a2b2a94a2..798b9fe3e2 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergedEventAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingMergedEventAdapter.java @@ -16,13 +16,9 @@ import org.eclipse.ditto.json.JsonPointer; import org.eclipse.ditto.protocol.Adaptable; -import org.eclipse.ditto.protocol.EventsTopicPathBuilder; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.adapter.MergedEventAdapter; -import org.eclipse.ditto.protocol.Payload; -import org.eclipse.ditto.protocol.PayloadBuilder; -import org.eclipse.ditto.protocol.ProtocolFactory; -import org.eclipse.ditto.protocol.TopicPath; +import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.events.ThingMerged; @@ -33,7 +29,9 @@ final class ThingMergedEventAdapter extends AbstractThingAdapter implements MergedEventAdapter { private ThingMergedEventAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingMergedEventMappingStrategies(), headerTranslator, + super(MappingStrategiesFactory.getThingMergedEventMappingStrategies(), + SignalMapperFactory.newThingMergedEventSignalMapper(), + headerTranslator, ThingMergePathMatcher.getInstance()); } @@ -53,19 +51,4 @@ protected String getType(final Adaptable adaptable) { return payloadPathMatcher.match(path); } - @Override - protected Adaptable mapSignalToAdaptable(final ThingMerged event, final TopicPath.Channel channel) { - final EventsTopicPathBuilder eventsTopicPathBuilder = getEventTopicPathBuilderFor(event, channel); - - final PayloadBuilder payloadBuilder = Payload.newBuilder(event.getResourcePath()) - .withRevision(event.getRevision()); - event.getTimestamp().ifPresent(payloadBuilder::withTimestamp); - payloadBuilder.withValue(event.getValue()); - - return Adaptable.newBuilder(eventsTopicPathBuilder.build()) - .withPayload(payloadBuilder.build()) - .withHeaders(ProtocolFactory.newHeadersWithJsonMergePatchContentType(event.getDittoHeaders())) - .build(); - } - } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingModifyCommandAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingModifyCommandAdapter.java index 24a1b15dff..ff0a48e5e7 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingModifyCommandAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingModifyCommandAdapter.java @@ -17,10 +17,8 @@ import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.adapter.ModifyCommandAdapter; -import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.protocol.mapper.SignalMapper; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; +import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.commands.modify.ThingModifyCommand; /** @@ -29,12 +27,10 @@ final class ThingModifyCommandAdapter extends AbstractThingAdapter> implements ModifyCommandAdapter> { - private final SignalMapper> signalMapper = - SignalMapperFactory.newThingModifySignalMapper(); - - private ThingModifyCommandAdapter( - final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingModifyCommandMappingStrategies(), headerTranslator); + private ThingModifyCommandAdapter(final HeaderTranslator headerTranslator) { + super(MappingStrategiesFactory.getThingModifyCommandMappingStrategies(), + SignalMapperFactory.newThingModifySignalMapper(), + headerTranslator); } /** @@ -47,8 +43,4 @@ public static ThingModifyCommandAdapter of(final HeaderTranslator headerTranslat return new ThingModifyCommandAdapter(requireNonNull(headerTranslator)); } - @Override - public Adaptable mapSignalToAdaptable(final ThingModifyCommand command, final TopicPath.Channel channel) { - return signalMapper.mapSignalToAdaptable(command, channel); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingModifyCommandResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingModifyCommandResponseAdapter.java index bc3e32f75e..2dc7fff750 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingModifyCommandResponseAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingModifyCommandResponseAdapter.java @@ -16,11 +16,10 @@ import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.adapter.ModifyCommandResponseAdapter; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.protocol.mapper.SignalMapper; +import org.eclipse.ditto.protocol.adapter.ModifyCommandResponseAdapter; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; +import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.commands.modify.ThingModifyCommandResponse; /** @@ -29,11 +28,10 @@ final class ThingModifyCommandResponseAdapter extends AbstractThingAdapter> implements ModifyCommandResponseAdapter> { - private final SignalMapper> - signalMapper = SignalMapperFactory.newThingModifyResponseSignalMapper(); - private ThingModifyCommandResponseAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingModifyCommandResponseMappingStrategies(), headerTranslator); + super(MappingStrategiesFactory.getThingModifyCommandResponseMappingStrategies(), + SignalMapperFactory.newThingModifyResponseSignalMapper(), + headerTranslator); } /** @@ -51,9 +49,4 @@ protected String getTypeCriterionAsString(final TopicPath topicPath) { return RESPONSES_CRITERION; } - @Override - protected Adaptable mapSignalToAdaptable(final ThingModifyCommandResponse signal, - final TopicPath.Channel channel) { - return signalMapper.mapSignalToAdaptable(signal, channel); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingQueryCommandAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingQueryCommandAdapter.java index d691102355..06f9cd5a34 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingQueryCommandAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingQueryCommandAdapter.java @@ -16,11 +16,10 @@ import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.adapter.QueryCommandAdapter; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.protocol.mapper.SignalMapper; +import org.eclipse.ditto.protocol.adapter.QueryCommandAdapter; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; +import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThings; import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommand; @@ -30,11 +29,10 @@ final class ThingQueryCommandAdapter extends AbstractThingAdapter> implements QueryCommandAdapter> { - private final SignalMapper> thingQuerySignalMapper = - SignalMapperFactory.newThingQuerySignalMapper(); - private ThingQueryCommandAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingQueryCommandMappingStrategies(), headerTranslator); + super(MappingStrategiesFactory.getThingQueryCommandMappingStrategies(), + SignalMapperFactory.newThingQuerySignalMapper(), + headerTranslator); } /** @@ -58,8 +56,4 @@ protected String getType(final Adaptable adaptable) { } } - @Override - public Adaptable mapSignalToAdaptable(final ThingQueryCommand command, final TopicPath.Channel channel) { - return thingQuerySignalMapper.mapSignalToAdaptable(command, channel); - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingQueryCommandResponseAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingQueryCommandResponseAdapter.java index 1dd8929fc4..315c0baa0b 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingQueryCommandResponseAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingQueryCommandResponseAdapter.java @@ -16,11 +16,10 @@ import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; -import org.eclipse.ditto.protocol.adapter.QueryCommandResponseAdapter; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.protocol.mapper.SignalMapper; +import org.eclipse.ditto.protocol.adapter.QueryCommandResponseAdapter; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; +import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommandResponse; /** @@ -29,13 +28,10 @@ final class ThingQueryCommandResponseAdapter extends AbstractThingAdapter> implements QueryCommandResponseAdapter> { - - private final SignalMapper> - thingQueryResponseSignalMapper = - SignalMapperFactory.newThingQueryResponseSignalMapper(); - private ThingQueryCommandResponseAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingQueryCommandResponseMappingStrategies(), headerTranslator); + super(MappingStrategiesFactory.getThingQueryCommandResponseMappingStrategies(), + SignalMapperFactory.newThingQueryResponseSignalMapper(), + headerTranslator); } /** @@ -53,10 +49,4 @@ protected String getTypeCriterionAsString(final TopicPath topicPath) { return RESPONSES_CRITERION; } - @Override - public Adaptable mapSignalToAdaptable(final ThingQueryCommandResponse commandResponse, - final TopicPath.Channel channel) { - return thingQueryResponseSignalMapper.mapSignalToAdaptable(commandResponse, channel); - - } } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingSearchCommandAdapter.java b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingSearchCommandAdapter.java index 28aa5277e9..a0c34367a6 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingSearchCommandAdapter.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/adapter/things/ThingSearchCommandAdapter.java @@ -21,9 +21,8 @@ import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.HeaderTranslator; import org.eclipse.ditto.protocol.TopicPath; -import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; -import org.eclipse.ditto.protocol.mapper.SignalMapper; import org.eclipse.ditto.protocol.mapper.SignalMapperFactory; +import org.eclipse.ditto.protocol.mappingstrategies.MappingStrategiesFactory; import org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand; /** @@ -32,12 +31,12 @@ * * @since 1.2.0 */ -public class ThingSearchCommandAdapter extends AbstractThingAdapter> { - - private final SignalMapper> signalMapper = SignalMapperFactory.newThingSearchSignalMapper(); +final class ThingSearchCommandAdapter extends AbstractThingAdapter> { private ThingSearchCommandAdapter(final HeaderTranslator headerTranslator) { - super(MappingStrategiesFactory.getThingSearchCommandMappingStrategies(), headerTranslator); + super(MappingStrategiesFactory.getThingSearchCommandMappingStrategies(), + SignalMapperFactory.newThingSearchSignalMapper(), + headerTranslator); } /** @@ -50,11 +49,6 @@ public static ThingSearchCommandAdapter of(final HeaderTranslator headerTranslat return new ThingSearchCommandAdapter(requireNonNull(headerTranslator)); } - @Override - public Adaptable mapSignalToAdaptable(final ThingSearchCommand command, final TopicPath.Channel channel) { - return signalMapper.mapSignalToAdaptable(command, channel); - } - @Override protected String getType(final Adaptable adaptable) { return ThingSearchCommand.TYPE_PREFIX + adaptable.getTopicPath().getSearchAction().orElse(null); diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/AbstractSignalMapper.java b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/AbstractSignalMapper.java index 20d5771ccf..7a86fcbbe6 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/AbstractSignalMapper.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/AbstractSignalMapper.java @@ -12,14 +12,16 @@ */ package org.eclipse.ditto.protocol.mapper; +import static org.eclipse.ditto.base.model.common.ConditionChecker.checkNotNull; + import org.eclipse.ditto.base.model.headers.DittoHeaders; +import org.eclipse.ditto.base.model.signals.Signal; import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.Payload; import org.eclipse.ditto.protocol.PayloadBuilder; import org.eclipse.ditto.protocol.ProtocolFactory; import org.eclipse.ditto.protocol.TopicPath; import org.eclipse.ditto.protocol.TopicPathBuilder; -import org.eclipse.ditto.base.model.signals.Signal; /** * Base class for all {@link SignalMapper}s. Constructs an {@link Adaptable} with data common to all signals @@ -49,6 +51,11 @@ public Adaptable mapSignalToAdaptable(final T signal, final TopicPath.Channel ch .build(); } + @Override + public TopicPath mapSignalToTopicPath(final T signal, final TopicPath.Channel channel) { + return getTopicPath(checkNotNull(signal, "signal"), checkNotNull(channel, "channel")); + } + /** * Generates the proper topic path for the given {@link Signal}. * diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SignalMapper.java b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SignalMapper.java index eaef4ea39a..d32ea58c56 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SignalMapper.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SignalMapper.java @@ -12,6 +12,7 @@ */ package org.eclipse.ditto.protocol.mapper; +import org.eclipse.ditto.base.model.signals.Signal; import org.eclipse.ditto.protocol.Adaptable; import org.eclipse.ditto.protocol.TopicPath; @@ -20,14 +21,25 @@ * * @param the type of the source signal */ -public interface SignalMapper { +public interface SignalMapper> { /** * Is called during the mapping from a signal to an {@link Adaptable}. * - * @param signal the source {@link org.eclipse.ditto.base.model.signals.Signal} from which to map an {@link Adaptable} - * @param channel the channel used to send the signal + * @param signal the source {@link Signal} from which to map an {@link Adaptable} + * @param channel the channel used to send the signal. * @return an {@link Adaptable} */ Adaptable mapSignalToAdaptable(T signal, TopicPath.Channel channel); + + /** + * Maps the provided signal {@code t} to its Ditto Protocol topic path. + * + * @param signal the source {@link Signal} from which to map the topic path. + * @param channel the channel used to send the signal. + * @return the corresponding topic path. + * @throws NullPointerException if any argument is {@code null}. + * @since 2.1.0 + */ + TopicPath mapSignalToTopicPath(T signal, TopicPath.Channel channel); } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SignalMapperFactory.java b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SignalMapperFactory.java index 9ff369d5c1..81ad891cd9 100644 --- a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SignalMapperFactory.java +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SignalMapperFactory.java @@ -13,13 +13,13 @@ package org.eclipse.ditto.protocol.mapper; import org.eclipse.ditto.connectivity.model.signals.announcements.ConnectivityAnnouncement; +import org.eclipse.ditto.messages.model.signals.commands.MessageCommand; +import org.eclipse.ditto.messages.model.signals.commands.MessageCommandResponse; import org.eclipse.ditto.policies.model.signals.announcements.PolicyAnnouncement; import org.eclipse.ditto.policies.model.signals.commands.modify.PolicyModifyCommand; import org.eclipse.ditto.policies.model.signals.commands.modify.PolicyModifyCommandResponse; import org.eclipse.ditto.policies.model.signals.commands.query.PolicyQueryCommand; import org.eclipse.ditto.policies.model.signals.commands.query.PolicyQueryCommandResponse; -import org.eclipse.ditto.messages.model.signals.commands.MessageCommand; -import org.eclipse.ditto.messages.model.signals.commands.MessageCommandResponse; import org.eclipse.ditto.things.model.signals.commands.modify.MergeThing; import org.eclipse.ditto.things.model.signals.commands.modify.MergeThingResponse; import org.eclipse.ditto.things.model.signals.commands.modify.ThingModifyCommand; @@ -28,7 +28,10 @@ import org.eclipse.ditto.things.model.signals.commands.query.RetrieveThingsResponse; import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommand; import org.eclipse.ditto.things.model.signals.commands.query.ThingQueryCommandResponse; +import org.eclipse.ditto.things.model.signals.events.ThingEvent; +import org.eclipse.ditto.things.model.signals.events.ThingMerged; import org.eclipse.ditto.thingsearch.model.signals.commands.ThingSearchCommand; +import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent; /** * Factory class that instantiates all available {@link SignalMapper}s. @@ -45,18 +48,26 @@ public static SignalMapper> newThingModifySignalMapper() { return new ThingModifySignalMapper(); } - public static SignalMapper newThingMergeSignalMapper() { - return new ThingMergeSignalMapper(); - } - public static SignalMapper> newThingModifyResponseSignalMapper() { return new ThingModifyResponseSignalMapper(); } + public static SignalMapper> newThingEventSignalMapper() { + return new ThingEventSignalMapper(); + } + + public static SignalMapper newThingMergeSignalMapper() { + return new ThingMergeSignalMapper(); + } + public static SignalMapper newThingMergeResponseSignalMapper() { return new ThingMergeResponseSignalMapper(); } + public static SignalMapper newThingMergedEventSignalMapper() { + return new ThingMergedEventSignalMapper(); + } + public static SignalMapper> newThingQuerySignalMapper() { return new ThingQuerySignalMapper(); } @@ -65,6 +76,10 @@ public static SignalMapper> newThingQueryResponseSi return new ThingQueryResponseSignalMapper(); } + public static SignalMapper> newSubscriptionEventSignalMapper() { + return new SubscriptionEventSignalMapper(); + } + public static SignalMapper newRetrieveThingsSignalMapper() { return new RetrieveThingsSignalMapper(); } diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SubscriptionEventSignalMapper.java b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SubscriptionEventSignalMapper.java new file mode 100644 index 0000000000..75d3e3d8ff --- /dev/null +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/SubscriptionEventSignalMapper.java @@ -0,0 +1,87 @@ +/* + * 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.protocol.mapper; + +import org.eclipse.ditto.base.model.headers.DittoHeaders; +import org.eclipse.ditto.json.JsonFactory; +import org.eclipse.ditto.json.JsonFieldDefinition; +import org.eclipse.ditto.json.JsonObjectBuilder; +import org.eclipse.ditto.protocol.PayloadBuilder; +import org.eclipse.ditto.protocol.ProtocolFactory; +import org.eclipse.ditto.protocol.TopicPath; +import org.eclipse.ditto.protocol.UnknownEventException; +import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionComplete; +import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionCreated; +import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionEvent; +import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionFailed; +import org.eclipse.ditto.thingsearch.model.signals.events.SubscriptionHasNextPage; + +final class SubscriptionEventSignalMapper extends AbstractSignalMapper> { + + private static final JsonFieldDefinition SUBSCRIPTION_ID = SubscriptionEvent.JsonFields.SUBSCRIPTION_ID; + + @Override + void enhancePayloadBuilder(final SubscriptionEvent signal, final PayloadBuilder payloadBuilder) { + final JsonObjectBuilder payloadContentBuilder = JsonFactory.newObjectBuilder(); + if (signal instanceof SubscriptionCreated) { + SubscriptionCreated createdEvent = (SubscriptionCreated) signal; + payloadContentBuilder.set(SUBSCRIPTION_ID, createdEvent.getSubscriptionId()); + + } else if (signal instanceof SubscriptionComplete) { + SubscriptionComplete completedEvent = (SubscriptionComplete) signal; + payloadContentBuilder.set(SUBSCRIPTION_ID, completedEvent.getSubscriptionId()); + + } else if (signal instanceof SubscriptionFailed) { + SubscriptionFailed failedEvent = (SubscriptionFailed) signal; + payloadContentBuilder + .set(SUBSCRIPTION_ID, failedEvent.getSubscriptionId()) + .set(SubscriptionFailed.JsonFields.ERROR, failedEvent.getError().toJson()); + + } else if (signal instanceof SubscriptionHasNextPage) { + SubscriptionHasNextPage hasNextEvent = (SubscriptionHasNextPage) signal; + payloadContentBuilder + .set(SUBSCRIPTION_ID, hasNextEvent.getSubscriptionId()) + .set(SubscriptionHasNextPage.JsonFields.ITEMS, hasNextEvent.getItems()); + + } else { + throw UnknownEventException.newBuilder(signal.getClass().getCanonicalName()).build(); + } + payloadBuilder.withValue(payloadContentBuilder.build()); + } + + @Override + DittoHeaders enhanceHeaders(final SubscriptionEvent signal) { + return ProtocolFactory.newHeadersWithJsonContentType(signal.getDittoHeaders()); + } + + @Override + TopicPath getTopicPath(final SubscriptionEvent signal, final TopicPath.Channel channel) { + final TopicPath topicPath; + if (signal instanceof SubscriptionCreated) { + topicPath = TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().twin().search().generated().build(); + + } else if (signal instanceof SubscriptionComplete) { + topicPath = TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().twin().search().complete().build(); + + } else if (signal instanceof SubscriptionFailed) { + topicPath = TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().twin().search().failed().build(); + + } else if (signal instanceof SubscriptionHasNextPage) { + topicPath = TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().twin().search().hasNext().build(); + } else { + throw UnknownEventException.newBuilder(signal.getClass().getCanonicalName()).build(); + } + return topicPath; + } + +} diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/ThingEventSignalMapper.java b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/ThingEventSignalMapper.java new file mode 100644 index 0000000000..6fbc5b5feb --- /dev/null +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/ThingEventSignalMapper.java @@ -0,0 +1,94 @@ +/* + * 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.protocol.mapper; + +import java.util.Locale; +import java.util.Optional; + +import org.eclipse.ditto.base.model.headers.DittoHeaders; +import org.eclipse.ditto.json.JsonValue; +import org.eclipse.ditto.protocol.EventsTopicPathBuilder; +import org.eclipse.ditto.protocol.PayloadBuilder; +import org.eclipse.ditto.protocol.ProtocolFactory; +import org.eclipse.ditto.protocol.TopicPath; +import org.eclipse.ditto.protocol.TopicPathBuilder; +import org.eclipse.ditto.protocol.UnknownChannelException; +import org.eclipse.ditto.protocol.UnknownEventException; +import org.eclipse.ditto.things.model.signals.events.ThingEvent; + +final class ThingEventSignalMapper extends AbstractSignalMapper> { + + @Override + void enhancePayloadBuilder(final ThingEvent signal, final PayloadBuilder payloadBuilder) { + payloadBuilder.withRevision(signal.getRevision()) + .withTimestamp(signal.getTimestamp().orElse(null)); + final Optional value = + signal.getEntity(signal.getDittoHeaders().getSchemaVersion().orElse(signal.getLatestSchemaVersion())); + value.ifPresent(payloadBuilder::withValue); + } + + @Override + DittoHeaders enhanceHeaders(final ThingEvent signal) { + final Optional value = + signal.getEntity(signal.getDittoHeaders().getSchemaVersion().orElse(signal.getLatestSchemaVersion())); + if (value.isPresent()) { + return ProtocolFactory.newHeadersWithJsonContentType(signal.getDittoHeaders()); + } else { + return signal.getDittoHeaders(); + } + } + + @Override + TopicPath getTopicPath(final ThingEvent signal, final TopicPath.Channel channel) { + final EventsTopicPathBuilder topicPathBuilder = getEventsTopicPathBuilderOrThrow(signal, channel); + final String eventName = getLowerCaseEventName(signal); + if (isAction(eventName, TopicPath.Action.CREATED)) { + topicPathBuilder.created(); + } else if (isAction(eventName, TopicPath.Action.MODIFIED)) { + topicPathBuilder.modified(); + } else if (isAction(eventName, TopicPath.Action.DELETED)) { + topicPathBuilder.deleted(); + } else if (isAction(eventName, TopicPath.Action.MERGED)) { + topicPathBuilder.merged(); + } else { + throw UnknownEventException.newBuilder(eventName).build(); + } + return topicPathBuilder.build(); + } + + private static EventsTopicPathBuilder getEventsTopicPathBuilderOrThrow(final ThingEvent event, + final TopicPath.Channel channel) { + + TopicPathBuilder topicPathBuilder = ProtocolFactory.newTopicPathBuilder(event.getEntityId()); + if (TopicPath.Channel.TWIN == channel) { + topicPathBuilder = topicPathBuilder.twin(); + } else if (TopicPath.Channel.LIVE == channel) { + topicPathBuilder = topicPathBuilder.live(); + } else { + throw UnknownChannelException.newBuilder(channel, event.getType()) + .dittoHeaders(event.getDittoHeaders()) + .build(); + } + return topicPathBuilder.events(); + } + + private static String getLowerCaseEventName(final ThingEvent thingEvent) { + final Class thingEventClass = thingEvent.getClass(); + final String eventClassSimpleName = thingEventClass.getSimpleName(); + return eventClassSimpleName.toLowerCase(Locale.ENGLISH); + } + + private static boolean isAction(final String eventName, final TopicPath.Action expectedAction) { + return eventName.contains(expectedAction.getName()); + } +} diff --git a/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/ThingMergedEventSignalMapper.java b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/ThingMergedEventSignalMapper.java new file mode 100644 index 0000000000..1c7252175d --- /dev/null +++ b/protocol/src/main/java/org/eclipse/ditto/protocol/mapper/ThingMergedEventSignalMapper.java @@ -0,0 +1,56 @@ +/* + * 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.protocol.mapper; + +import org.eclipse.ditto.base.model.headers.DittoHeaders; +import org.eclipse.ditto.protocol.PayloadBuilder; +import org.eclipse.ditto.protocol.ProtocolFactory; +import org.eclipse.ditto.protocol.TopicPath; +import org.eclipse.ditto.protocol.TopicPathBuilder; +import org.eclipse.ditto.protocol.UnknownChannelException; +import org.eclipse.ditto.things.model.signals.events.ThingMerged; + +final class ThingMergedEventSignalMapper extends AbstractSignalMapper { + + @Override + void enhancePayloadBuilder(final ThingMerged signal, final PayloadBuilder payloadBuilder) { + payloadBuilder.withRevision(signal.getRevision()) + .withTimestamp(signal.getTimestamp().orElse(null)) + .withValue(signal.getValue()); + } + + @Override + DittoHeaders enhanceHeaders(final ThingMerged signal) { + return ProtocolFactory.newHeadersWithJsonMergePatchContentType(signal.getDittoHeaders()); + } + + @Override + TopicPath getTopicPath(final ThingMerged signal, final TopicPath.Channel channel) { + + TopicPathBuilder topicPathBuilder = ProtocolFactory.newTopicPathBuilder(signal.getEntityId()) + .things(); + if (TopicPath.Channel.TWIN == channel) { + topicPathBuilder = topicPathBuilder.twin(); + } else if (TopicPath.Channel.LIVE == channel) { + topicPathBuilder = topicPathBuilder.live(); + } else { + throw UnknownChannelException.newBuilder(channel, signal.getType()) + .dittoHeaders(signal.getDittoHeaders()) + .build(); + } + return topicPathBuilder + .events() + .merged() + .build(); + } +} diff --git a/protocol/src/test/java/org/eclipse/ditto/protocol/adapter/DittoProtocolAdapterParameterizedTest.java b/protocol/src/test/java/org/eclipse/ditto/protocol/adapter/DittoProtocolAdapterParameterizedTest.java index 4a763a2956..62a87eacc6 100644 --- a/protocol/src/test/java/org/eclipse/ditto/protocol/adapter/DittoProtocolAdapterParameterizedTest.java +++ b/protocol/src/test/java/org/eclipse/ditto/protocol/adapter/DittoProtocolAdapterParameterizedTest.java @@ -246,8 +246,8 @@ public void setUp() { when(policyCommandAdapterProvider.getErrorResponseAdapter()) .thenReturn(policyErrorResponseAdapter); - final AdapterResolver adapterResolver = mock(AdapterResolver.class); - + final AdapterResolver adapterResolver = new DefaultAdapterResolver(thingCommandAdapterProvider, + policyCommandAdapterProvider, connectivityCommandAdapterProvider, acknowledgementAdapterProvider); underTest = DittoProtocolAdapter.newInstance(HeaderTranslator.empty(), thingCommandAdapterProvider, policyCommandAdapterProvider, connectivityCommandAdapterProvider, acknowledgementAdapterProvider, adapterResolver); diff --git a/protocol/src/test/java/org/eclipse/ditto/protocol/adapter/things/SearchErrorResponseAdapterTest.java b/protocol/src/test/java/org/eclipse/ditto/protocol/adapter/things/SearchErrorResponseAdapterTest.java new file mode 100644 index 0000000000..31cf831a55 --- /dev/null +++ b/protocol/src/test/java/org/eclipse/ditto/protocol/adapter/things/SearchErrorResponseAdapterTest.java @@ -0,0 +1,92 @@ +/* + * 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.protocol.adapter.things; + +import org.eclipse.ditto.base.model.common.HttpStatus; +import org.eclipse.ditto.base.model.exceptions.DittoRuntimeException; +import org.eclipse.ditto.base.model.headers.DittoHeaders; +import org.eclipse.ditto.base.model.json.FieldType; +import org.eclipse.ditto.base.model.signals.ErrorRegistry; +import org.eclipse.ditto.base.model.signals.GlobalErrorRegistry; +import org.eclipse.ditto.json.JsonPointer; +import org.eclipse.ditto.protocol.Adaptable; +import org.eclipse.ditto.protocol.Payload; +import org.eclipse.ditto.protocol.TestConstants; +import org.eclipse.ditto.protocol.TopicPath; +import org.eclipse.ditto.protocol.adapter.DittoProtocolAdapter; +import org.eclipse.ditto.protocol.adapter.ProtocolAdapterTest; +import org.eclipse.ditto.thingsearch.model.signals.commands.SearchErrorResponse; +import org.eclipse.ditto.thingsearch.model.signals.commands.exceptions.InvalidOptionException; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit test for {@link SearchErrorResponseAdapter}. + */ +public class SearchErrorResponseAdapterTest implements ProtocolAdapterTest { + + private SearchErrorResponseAdapter underTest; + private DittoRuntimeException dittoRuntimeException; + + @Before + public void setUp() { + final ErrorRegistry errorRegistry = GlobalErrorRegistry.getInstance(); + underTest = SearchErrorResponseAdapter.of(DittoProtocolAdapter.getHeaderTranslator(), errorRegistry); + dittoRuntimeException = InvalidOptionException.newBuilder() + .message("the message") + .description("the description") + .build(); + } + + @Test + public void testFromAdaptable() { + final SearchErrorResponse expected = + SearchErrorResponse.of(dittoRuntimeException, DittoHeaders.empty()); + + final TopicPath topicPath = + TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().none().search().error().build(); + final JsonPointer path = JsonPointer.empty(); + + final Adaptable adaptable = Adaptable.newBuilder(topicPath) + .withPayload(Payload.newBuilder(path) + .withValue(dittoRuntimeException.toJson(FieldType.regularOrSpecial())) + .build()) + .withHeaders(TestConstants.HEADERS_V_2) + .build(); + final SearchErrorResponse actual = underTest.fromAdaptable(adaptable); + + assertWithExternalHeadersThat(actual).isEqualTo(expected); + } + + @Test + public void testToAdaptable() { + final SearchErrorResponse errorResponse = + SearchErrorResponse.of(dittoRuntimeException, DittoHeaders.empty()); + + final TopicPath topicPath = + TopicPath.fromNamespace(TopicPath.ID_PLACEHOLDER).things().none().search().error().build(); + final JsonPointer path = JsonPointer.empty(); + + final Adaptable expected = Adaptable.newBuilder(topicPath) + .withPayload(Payload.newBuilder(path) + .withValue(dittoRuntimeException.toJson(FieldType.regularOrSpecial())) + .withStatus(HttpStatus.BAD_REQUEST) + .build()) + .withHeaders(TestConstants.HEADERS_V_2) + .build(); + + final Adaptable actual = underTest.toAdaptable(errorResponse, TopicPath.Channel.TWIN); + + assertWithExternalHeadersThat(actual).isEqualTo(expected); + } +}