Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2017 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.messaging.amqp;
import static org.eclipse.ditto.base.model.common.ConditionChecker.checkArgument;
import static org.eclipse.ditto.base.model.common.ConditionChecker.checkNotNull;
import java.nio.ByteBuffer;
import java.time.Instant;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import javax.jms.BytesMessage;
import javax.jms.CompletionListener;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import org.apache.qpid.jms.JmsOperationTimedOutException;
import org.apache.qpid.jms.message.JmsMessage;
import org.eclipse.ditto.base.model.acks.AcknowledgementLabel;
import org.eclipse.ditto.base.model.auth.AuthorizationContext;
import org.eclipse.ditto.base.model.common.HttpStatus;
import org.eclipse.ditto.base.model.common.Placeholders;
import org.eclipse.ditto.base.model.entity.id.EntityId;
import org.eclipse.ditto.base.model.entity.id.WithEntityId;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.base.model.signals.Signal;
import org.eclipse.ditto.base.model.signals.acks.Acknowledgement;
import org.eclipse.ditto.connectivity.api.ExternalMessage;
import org.eclipse.ditto.connectivity.model.Connection;
import org.eclipse.ditto.connectivity.model.ConnectivityModelFactory;
import org.eclipse.ditto.connectivity.model.ConnectivityStatus;
import org.eclipse.ditto.connectivity.model.GenericTarget;
import org.eclipse.ditto.connectivity.model.MessageSendingFailedException;
import org.eclipse.ditto.connectivity.model.ResourceStatus;
import org.eclipse.ditto.connectivity.model.Target;
import org.eclipse.ditto.connectivity.service.config.Amqp10Config;
import org.eclipse.ditto.connectivity.service.config.ConnectivityConfig;
import org.eclipse.ditto.connectivity.service.messaging.BasePublisherActor;
import org.eclipse.ditto.connectivity.service.messaging.ConnectivityStatusResolver;
import org.eclipse.ditto.connectivity.service.messaging.SendResult;
import org.eclipse.ditto.connectivity.service.messaging.amqp.status.ProducerClosedStatusReport;
import org.eclipse.ditto.connectivity.service.messaging.backoff.BackOffActor;
import org.eclipse.ditto.connectivity.service.messaging.internal.ConnectionFailure;
import org.eclipse.ditto.internal.utils.akka.logging.ThreadSafeDittoLoggingAdapter;
import org.eclipse.ditto.internal.utils.config.InstanceIdentifierSupplier;
import akka.Done;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.Status;
import akka.japi.Pair;
import akka.japi.pf.PFBuilder;
import akka.japi.pf.ReceiveBuilder;
import akka.stream.KillSwitch;
import akka.stream.KillSwitches;
import akka.stream.Materializer;
import akka.stream.OverflowStrategy;
import akka.stream.QueueOfferResult;
import akka.stream.UniqueKillSwitch;
import akka.stream.javadsl.Keep;
import akka.stream.javadsl.Source;
import akka.stream.javadsl.SourceQueueWithComplete;
import akka.stream.scaladsl.Sink;
/**
* Responsible for creating JMS {@link MessageProducer}s and sending {@link ExternalMessage}s as JMSMessages to those.
*/
public final class AmqpPublisherActor extends BasePublisherActor {
/**
* The name prefix of this Actor in the ActorSystem.
*/
static final String ACTOR_NAME_PREFIX = "amqpPublisherActor";
private static final String TOO_MANY_IN_FLIGHT_MESSAGE_DESCRIPTION = "This can have the following reasons:\n" +
"a) The AMQP 1.0 consumer does not consume the messages fast enough.\n" +
"b) The client count of this connection is not configured high enough.";
private final Session session;
private final LinkedHashMap dynamicTargets;
private final Map staticTargets;
private final int producerCacheSize;
private final ActorRef backOffActor;
private final SourceQueueWithComplete> sourceQueue;
private final KillSwitch killSwitch;
private boolean isInBackOffMode;
@SuppressWarnings("unused")
private AmqpPublisherActor(final Connection connection,
final Session session,
final ConnectivityStatusResolver connectivityStatusResolver,
final ConnectivityConfig connectivityConfig) {
super(connection, connectivityStatusResolver, connectivityConfig);
this.session = checkNotNull(session, "session");
final Executor jmsDispatcher = JMSConnectionHandlingActor.getOwnDispatcher(getContext().system());
final Amqp10Config config = connectionConfig.getAmqp10Config();
final Materializer materializer = Materializer.createMaterializer(this::getContext);
final Pair>, UniqueKillSwitch> materialized =
Source.>queue(config.getPublisherConfig().getMaxQueueSize(),
OverflowStrategy.dropNew())
.mapAsync(config.getPublisherConfig().getParallelism(),
msg -> triggerPublishAsync(msg, jmsDispatcher))
.recover(new PFBuilder()
// the "Done" instance is not used, this just means to not fail the stream for any Throwables
.matchAny(x -> Done.getInstance())
.build()
)
.viaMat(KillSwitches.single(), Keep.both())
.toMat(Sink.ignore(), Keep.left())
.run(materializer);
sourceQueue = materialized.first();
killSwitch = materialized.second();
staticTargets = new HashMap<>();
dynamicTargets = new LinkedHashMap<>(); // insertion order important for maintenance of producer cache
producerCacheSize = checkArgument(config.getProducerCacheSize(), i -> i > 0,
() -> "producer-cache-size must be 1 or more");
backOffActor = getContext().actorOf(BackOffActor.props(config.getBackOffConfig()));
isInBackOffMode = false;
}
/**
* Wrap 'publishing the message' in a Future for async map stage in stream.
*
* @param messageToPublish The Element in the Stream, the message to publish and its context.
* @param jmsDispatcher Executor, which triggers the async publishing via JMS.
* @return A future, which is done, when the publishing was triggered.
*/
private static CompletableFuture