All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.ditto.connectivity.service.util.ConnectionPubSub Maven / Gradle / Ivy

/*
 * Copyright (c) 2022 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.connectivity.service.util;

import java.util.List;
import java.util.concurrent.CompletionStage;

import javax.annotation.Nullable;

import org.eclipse.ditto.base.model.headers.DittoHeaderDefinition;
import org.eclipse.ditto.base.model.headers.DittoHeadersSettable;
import org.eclipse.ditto.base.model.signals.Signal;
import org.eclipse.ditto.connectivity.model.ConnectionId;
import org.eclipse.ditto.internal.utils.pubsub.DistributedPub;
import org.eclipse.ditto.internal.utils.pubsub.DistributedSub;
import org.eclipse.ditto.internal.utils.pubsub.api.SubAck;

import akka.actor.AbstractExtensionId;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.ExtendedActorSystem;
import akka.actor.Extension;

/**
 * Pub-sub for messages between client actors of a connection.
 */
public final class ConnectionPubSub implements Extension {

    private static final ExtensionId EXTENSION_ID = new ExtensionId();

    private final DistributedPub> pub;
    private final DistributedSub sub;

    private ConnectionPubSub(final DistributedPub> pub, final DistributedSub sub) {
        this.pub = pub;
        this.sub = sub;
    }

    /**
     * Look up the connection pub sub extension.
     *
     * @param system the actor system.
     * @return the connection pub sub extension of the actor system.
     */
    public static ConnectionPubSub get(final ActorSystem system) {
        return EXTENSION_ID.get(system);
    }

    /**
     * Publish a search signal for the responsible client actor.
     *
     * @param signal the signal.
     * @param connectionId the connection ID.
     * @param groupIndexKey the group index key to choose the responsible client actor, either the entity ID or the
     * subscription ID prefix.
     * @param sender the sender of the signal.
     */
    public void publishSignal(final Signal signal, final ConnectionId connectionId, final CharSequence groupIndexKey,
            @Nullable final ActorRef sender) {
        pub.publish(setConnectionId(signal, connectionId), groupIndexKey, sender);
    }

    /**
     * Subscribe as a client actor.
     *
     * @param connectionId connection ID of the client actor.
     * @param clientActor the client actor.
     * @param resubscribe whether this is a resubscription.
     * @return a future that completes with the consistency check result if it is a resubscription or {@code true}
     * otherwise.
     */
    public CompletionStage subscribe(final ConnectionId connectionId, final ActorRef clientActor,
            final boolean resubscribe) {
        final var idString = connectionId.toString();
        return sub.subscribeWithFilterAndGroup(List.of(idString), clientActor, null, idString, resubscribe)
                .thenApply(SubAck::isConsistent);
    }

    /**
     * Unsubscribe as a client actor.
     *
     * @param connectionId connection ID of the client actor.
     * @param clientActor the client actor.
     * @return a future that completes or fails according to whether unsubscription is successful.
     * otherwise.
     */
    public CompletionStage unsubscribe(final ConnectionId connectionId, final ActorRef clientActor) {
        final var idString = connectionId.toString();
        return sub.unsubscribeWithAck(List.of(idString), clientActor).thenApply(unsubAck -> null);
    }

    private static > T setConnectionId(final DittoHeadersSettable signal,
            final ConnectionId connectionId) {
        return signal.setDittoHeaders(
                signal.getDittoHeaders()
                        .toBuilder()
                        .putHeader(DittoHeaderDefinition.CONNECTION_ID.getKey(), connectionId)
                        .build()
        );
    }

    private static final class ExtensionId extends AbstractExtensionId {

        private ExtensionId() {}

        @Override
        public ConnectionPubSub createExtension(final ExtendedActorSystem system) {
            final var factory = ConnectionPubSubFactory.of(system);
            return new ConnectionPubSub(factory.startDistributedPub(), factory.startDistributedSub());
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy