Please wait. This can take some minutes ...
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.
com.arangodb.shaded.vertx.core.eventbus.impl.EventBusImpl Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2022 Contributors to the Eclipse Foundation
*
* 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, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package com.arangodb.shaded.vertx.core.eventbus.impl;
import com.arangodb.shaded.vertx.core.*;
import com.arangodb.shaded.vertx.core.eventbus.*;
import com.arangodb.shaded.vertx.core.impl.ContextInternal;
import com.arangodb.shaded.vertx.core.impl.VertxInternal;
import com.arangodb.shaded.vertx.core.impl.utils.ConcurrentCyclicSequence;
import com.arangodb.shaded.vertx.core.spi.metrics.EventBusMetrics;
import com.arangodb.shaded.vertx.core.spi.metrics.MetricsProvider;
import com.arangodb.shaded.vertx.core.spi.metrics.VertxMetrics;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Function;
/**
* A local event bus implementation
*
* @author Tim Fox T
*/
public class EventBusImpl implements EventBusInternal, MetricsProvider {
private static final AtomicReferenceFieldUpdater OUTBOUND_INTERCEPTORS_UPDATER = AtomicReferenceFieldUpdater.newUpdater(EventBusImpl.class, Handler[].class, "outboundInterceptors");
private static final AtomicReferenceFieldUpdater INBOUND_INTERCEPTORS_UPDATER = AtomicReferenceFieldUpdater.newUpdater(EventBusImpl.class, Handler[].class, "inboundInterceptors");
private volatile Handler[] outboundInterceptors = new Handler[0];
private volatile Handler[] inboundInterceptors = new Handler[0];
private final AtomicLong replySequence = new AtomicLong(0);
protected final VertxInternal vertx;
protected final EventBusMetrics metrics;
protected final ConcurrentMap> handlerMap = new ConcurrentHashMap<>();
protected final CodecManager codecManager = new CodecManager();
protected volatile boolean started;
public EventBusImpl(VertxInternal vertx) {
VertxMetrics metrics = vertx.metricsSPI();
this.vertx = vertx;
this.metrics = metrics != null ? metrics.createEventBusMetrics() : null;
}
@Override
public EventBus addOutboundInterceptor(Handler> interceptor) {
addInterceptor(OUTBOUND_INTERCEPTORS_UPDATER, Objects.requireNonNull(interceptor));
return this;
}
@Override
public EventBus addInboundInterceptor(Handler> interceptor) {
addInterceptor(INBOUND_INTERCEPTORS_UPDATER, Objects.requireNonNull(interceptor));
return this;
}
@Override
public EventBus removeOutboundInterceptor(Handler> interceptor) {
removeInterceptor(OUTBOUND_INTERCEPTORS_UPDATER, Objects.requireNonNull(interceptor));
return this;
}
@Override
public EventBus removeInboundInterceptor(Handler> interceptor) {
removeInterceptor(INBOUND_INTERCEPTORS_UPDATER, Objects.requireNonNull(interceptor));
return this;
}
Handler[] inboundInterceptors() {
return inboundInterceptors;
}
Handler[] outboundInterceptors() {
return outboundInterceptors;
}
@Override
public EventBus clusterSerializableChecker(Function classNamePredicate) {
codecManager.clusterSerializableCheck(classNamePredicate);
return this;
}
@Override
public EventBus serializableChecker(Function classNamePredicate) {
codecManager.serializableCheck(classNamePredicate);
return this;
}
@Override
public synchronized void start(Promise promise) {
if (started) {
throw new IllegalStateException("Already started");
}
started = true;
promise.complete();
}
@Override
public EventBus send(String address, Object message) {
return send(address, message, new DeliveryOptions());
}
@Override
public EventBus send(String address, Object message, DeliveryOptions options) {
MessageImpl msg = createMessage(true, address, options.getHeaders(), message, options.getCodecName());
sendOrPubInternal(msg, options, null, null);
return this;
}
@Override
public Future> request(String address, Object message, DeliveryOptions options) {
MessageImpl msg = createMessage(true, address, options.getHeaders(), message, options.getCodecName());
ReplyHandler handler = createReplyHandler(msg, true, options);
sendOrPubInternal(msg, options, handler, null);
return handler.result();
}
@Override
public MessageProducer sender(String address) {
Objects.requireNonNull(address, "address");
return new MessageProducerImpl<>(vertx, address, true, new DeliveryOptions());
}
@Override
public MessageProducer sender(String address, DeliveryOptions options) {
Objects.requireNonNull(address, "address");
Objects.requireNonNull(options, "options");
return new MessageProducerImpl<>(vertx, address, true, options);
}
@Override
public MessageProducer publisher(String address) {
Objects.requireNonNull(address, "address");
return new MessageProducerImpl<>(vertx, address, false, new DeliveryOptions());
}
@Override
public MessageProducer publisher(String address, DeliveryOptions options) {
Objects.requireNonNull(address, "address");
Objects.requireNonNull(options, "options");
return new MessageProducerImpl<>(vertx, address, false, options);
}
@Override
public EventBus publish(String address, Object message) {
return publish(address, message, new DeliveryOptions());
}
@Override
public EventBus publish(String address, Object message, DeliveryOptions options) {
sendOrPubInternal(createMessage(false, address, options.getHeaders(), message, options.getCodecName()), options, null, null);
return this;
}
@Override
public MessageConsumer consumer(String address) {
checkStarted();
Objects.requireNonNull(address, "address");
return new MessageConsumerImpl<>(vertx, vertx.getOrCreateContext(), this, address, false);
}
@Override
public MessageConsumer consumer(String address, Handler> handler) {
Objects.requireNonNull(handler, "handler");
MessageConsumer consumer = consumer(address);
consumer.handler(handler);
return consumer;
}
@Override
public MessageConsumer localConsumer(String address) {
checkStarted();
Objects.requireNonNull(address, "address");
return new MessageConsumerImpl<>(vertx, vertx.getOrCreateContext(), this, address, true);
}
@Override
public MessageConsumer localConsumer(String address, Handler> handler) {
Objects.requireNonNull(handler, "handler");
MessageConsumer consumer = localConsumer(address);
consumer.handler(handler);
return consumer;
}
@Override
public EventBus registerCodec(MessageCodec codec) {
codecManager.registerCodec(codec);
return this;
}
@Override
public EventBus unregisterCodec(String name) {
codecManager.unregisterCodec(name);
return this;
}
@Override
public EventBus registerDefaultCodec(Class clazz, MessageCodec codec) {
codecManager.registerDefaultCodec(clazz, codec);
return this;
}
@Override
public EventBus unregisterDefaultCodec(Class clazz) {
codecManager.unregisterDefaultCodec(clazz);
return this;
}
@Override
public EventBus codecSelector(Function selector) {
codecManager.codecSelector(selector);
return this;
}
@Override
public void close(Promise promise) {
if (!started) {
promise.complete();
return;
}
unregisterAll().onComplete(ar -> {
if (metrics != null) {
metrics.close();
}
promise.handle(ar);
});
}
@Override
public boolean isMetricsEnabled() {
return metrics != null;
}
@Override
public EventBusMetrics getMetrics() {
return metrics;
}
public MessageImpl createMessage(boolean send, String address, MultiMap headers, Object body, String codecName) {
Objects.requireNonNull(address, "no null address accepted");
MessageCodec codec = codecManager.lookupCodec(body, codecName, true);
@SuppressWarnings("unchecked")
MessageImpl msg = new MessageImpl(address, headers, body, codec, send, this);
return msg;
}
protected HandlerHolder addRegistration(String address, HandlerRegistration registration, boolean replyHandler, boolean localOnly, Promise promise) {
HandlerHolder holder = addLocalRegistration(address, registration, replyHandler, localOnly);
onLocalRegistration(holder, promise);
return holder;
}
protected void onLocalRegistration(HandlerHolder handlerHolder, Promise promise) {
if (promise != null) {
promise.complete();
}
}
private HandlerHolder addLocalRegistration(String address, HandlerRegistration registration,
boolean replyHandler, boolean localOnly) {
Objects.requireNonNull(address, "address");
ContextInternal context = registration.context;
HandlerHolder holder = createHandlerHolder(registration, replyHandler, localOnly, context);
ConcurrentCyclicSequence handlers = new ConcurrentCyclicSequence().add(holder);
ConcurrentCyclicSequence actualHandlers = handlerMap.merge(
address,
handlers,
(old, prev) -> old.add(prev.first()));
if (context.isDeployment()) {
context.addCloseHook(registration);
}
return holder;
}
protected HandlerHolder createHandlerHolder(HandlerRegistration registration, boolean replyHandler, boolean localOnly, ContextInternal context) {
return new HandlerHolder<>(registration, replyHandler, localOnly, context);
}
protected void removeRegistration(HandlerHolder handlerHolder, Promise promise) {
removeLocalRegistration(handlerHolder);
onLocalUnregistration(handlerHolder, promise);
}
protected void onLocalUnregistration(HandlerHolder handlerHolder, Promise promise) {
promise.complete();
}
private void removeLocalRegistration(HandlerHolder holder) {
String address = holder.getHandler().address;
handlerMap.compute(address, (key, val) -> {
if (val == null) {
return null;
}
ConcurrentCyclicSequence next = val.remove(holder);
return next.size() == 0 ? null : next;
});
if (holder.setRemoved() && holder.getContext().deploymentID() != null) {
holder.getContext().removeCloseHook(holder.getHandler());
}
}
protected void sendReply(MessageImpl replyMessage, DeliveryOptions options, ReplyHandler replyHandler) {
if (replyMessage.address() == null) {
throw new IllegalStateException("address not specified");
} else {
sendOrPubInternal(new OutboundDeliveryContext<>(vertx.getOrCreateContext(), replyMessage, options, replyHandler, null));
}
}
protected void sendOrPub(OutboundDeliveryContext sendContext) {
sendLocally(sendContext);
}
protected void callCompletionHandlerAsync(Handler> completionHandler) {
if (completionHandler != null) {
vertx.runOnContext(v -> {
completionHandler.handle(Future.succeededFuture());
});
}
}
private void sendLocally(OutboundDeliveryContext sendContext) {
ReplyException failure = deliverMessageLocally(sendContext.message);
if (failure != null) {
sendContext.written(failure);
} else {
sendContext.written(null);
}
}
protected boolean isMessageLocal(MessageImpl msg) {
return true;
}
protected ReplyException deliverMessageLocally(MessageImpl msg) {
ConcurrentCyclicSequence handlers = handlerMap.get(msg.address());
boolean messageLocal = isMessageLocal(msg);
if (handlers != null) {
if (msg.isSend()) {
//Choose one
HandlerHolder holder = nextHandler(handlers, messageLocal);
if (metrics != null) {
metrics.messageReceived(msg.address(), !msg.isSend(), messageLocal, holder != null ? 1 : 0);
}
if (holder != null) {
holder.handler.receive(msg.copyBeforeReceive());
} else {
// RACY issue !!!!!
}
} else {
// Publish
if (metrics != null) {
metrics.messageReceived(msg.address(), !msg.isSend(), messageLocal, handlers.size());
}
for (HandlerHolder holder: handlers) {
if (messageLocal || !holder.isLocalOnly()) {
holder.handler.receive(msg.copyBeforeReceive());
}
}
}
return null;
} else {
if (metrics != null) {
metrics.messageReceived(msg.address(), !msg.isSend(), messageLocal, 0);
}
return new ReplyException(ReplyFailure.NO_HANDLERS, "No handlers for address " + msg.address);
}
}
protected HandlerHolder nextHandler(ConcurrentCyclicSequence handlers, boolean messageLocal) {
return handlers.next();
}
protected void checkStarted() {
if (!started) {
throw new IllegalStateException("Event Bus is not started");
}
}
protected String generateReplyAddress() {
return "__vertx.reply." + Long.toString(replySequence.incrementAndGet());
}
ReplyHandler createReplyHandler(MessageImpl message,
boolean src,
DeliveryOptions options) {
long timeout = options.getSendTimeout();
String replyAddress = generateReplyAddress();
message.setReplyAddress(replyAddress);
ReplyHandler handler = new ReplyHandler<>(this, vertx.getOrCreateContext(), replyAddress, message.address, src, timeout);
handler.register();
return handler;
}
public OutboundDeliveryContext newSendContext(MessageImpl message, DeliveryOptions options,
ReplyHandler handler, Promise writePromise) {
return new OutboundDeliveryContext<>(vertx.getOrCreateContext(), message, options, handler, writePromise);
}
public void sendOrPubInternal(OutboundDeliveryContext senderCtx) {
checkStarted();
senderCtx.bus = this;
senderCtx.metrics = metrics;
senderCtx.next();
}
public void sendOrPubInternal(MessageImpl message, DeliveryOptions options,
ReplyHandler handler, Promise writePromise) {
checkStarted();
sendOrPubInternal(newSendContext(message, options, handler, writePromise));
}
private Future unregisterAll() {
// Unregister all handlers explicitly - don't rely on context hooks
List futures = new ArrayList<>();
for (ConcurrentCyclicSequence handlers : handlerMap.values()) {
for (HandlerHolder holder : handlers) {
futures.add(holder.getHandler().unregister());
}
}
return CompositeFuture.join(futures).mapEmpty();
}
private void addInterceptor(AtomicReferenceFieldUpdater updater, Handler interceptor) {
while (true) {
Handler[] interceptors = updater.get(this);
Handler[] copy = Arrays.copyOf(interceptors, interceptors.length + 1);
copy[interceptors.length] = interceptor;
if (updater.compareAndSet(this, interceptors, copy)) {
break;
}
}
}
private void removeInterceptor(AtomicReferenceFieldUpdater updater, Handler interceptor) {
while (true) {
Handler[] interceptors = updater.get(this);
int idx = -1;
for (int i = 0;i < interceptors.length;i++) {
if (interceptors[i].equals(interceptor)) {
idx = i;
break;
}
}
if (idx == -1) {
return;
}
Handler[] copy = new Handler[interceptors.length - 1];
System.arraycopy(interceptors, 0, copy, 0, idx);
System.arraycopy(interceptors, idx + 1, copy, idx, copy.length - idx);
if (updater.compareAndSet(this, interceptors, copy)) {
break;
}
}
}
}