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

io.mats3.matsbrokermonitor.broadcaster.MatsBrokerMonitorBroadcastAndControl Maven / Gradle / Ivy

package io.mats3.matsbrokermonitor.broadcaster;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.TreeMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.mats3.MatsEndpoint;
import io.mats3.MatsFactory;
import io.mats3.MatsFactory.MatsPlugin;
import io.mats3.MatsInitiator;
import io.mats3.matsbrokermonitor.api.MatsBrokerMonitor;
import io.mats3.matsbrokermonitor.api.MatsBrokerMonitor.BrokerInfo;
import io.mats3.matsbrokermonitor.api.MatsBrokerMonitor.BrokerInfoDto;
import io.mats3.matsbrokermonitor.api.MatsBrokerMonitor.MatsBrokerDestination;
import io.mats3.matsbrokermonitor.api.MatsBrokerMonitor.MatsBrokerDestinationDto;
import io.mats3.matsbrokermonitor.api.MatsBrokerMonitor.UpdateEvent;

/**
 * Rather simple utility which {@link MatsBrokerMonitor#registerListener(Consumer) subscribes} to {@link UpdateEvent}s
 * from the {@link MatsBrokerMonitor}, publishing them to the Mats fabric on the topic
 * {@link #BROADCAST_UPDATE_EVENT_TOPIC_ENDPOINT_ID}.
 * 

* Note that life cycling of the provided MatsBrokerMonitor is handled by this class: When the instance of this * class is {@link #start(MatsFactory) started} by the MatsFactory, it will invoke {@link MatsBrokerMonitor#start() * start} on the MatsBrokerMonitor, and when this instance is {@link #close() closed} by the MatsFactory, it will * {@link MatsBrokerMonitor#close() close} the MatsBrokerMonitor. * * * @author Endre Stølsvik 2022-11-12 10:33 - http://stolsvik.com/, [email protected] */ public class MatsBrokerMonitorBroadcastAndControl implements Closeable, MatsPlugin { private static final Logger log = LoggerFactory.getLogger(MatsBrokerMonitorBroadcastAndControl.class); /** * The EndpointId to which the update event is published. *

* Value is "mats.MatsBrokerMonitorBroadcastUpdate". */ public static final String BROADCAST_UPDATE_EVENT_TOPIC_ENDPOINT_ID = "mats.MatsBrokerMonitor.broadcastUpdate"; /** * The EndpointId to which one may request operations, currently forceUpdate. *

* Value is "mats.MatsBrokerMonitorControl". */ public static final String MATSBROKERMONITOR_CONTROL = "mats.MatsBrokerMonitor.control"; /** * Copied from MatsInterceptable.MatsLoggingInterceptor *

* We don't want all these updates to be logged on all the JVMs carrying MatsFactories, as it will be annoying noise * without much merit. */ private static final String SUPPRESS_LOGGING_TRACE_PROPERTY_KEY = "mats.SuppressLogging"; private final MatsBrokerMonitor _matsBrokerMonitor; /** * Creates a {@link MatsBrokerMonitorBroadcastAndControl} instance, installs it as a {@link MatsPlugin} on the * provided {@link MatsFactory}, and returns the instance - Note that lifecycling of the provided * {@link MatsBrokerMonitor} is handled by this class: When this instance is {@link #start(MatsFactory) started} * by the MatsFactory, it will invoke {@link MatsBrokerMonitor#start() start} on the MatsBrokerMonitor, and when * this instance is {@link #close() closed} by the MatsFactory, it will {@link MatsBrokerMonitor#close() close} the * MatsBrokerMonitor. * * @param matsBrokerMonitor * the {@link MatsBrokerMonitor} to listen to - note that life-cycle of this instance is managed by this * class, "forwarded" from the {@link MatsFactory}. * @param matsFactory * the {@link MatsFactory} to install the plugin on. * @return the created {@link MatsBrokerMonitorBroadcastAndControl} instance. */ public static MatsBrokerMonitorBroadcastAndControl install(MatsBrokerMonitor matsBrokerMonitor, MatsFactory matsFactory) { MatsBrokerMonitorBroadcastAndControl broadcastAndControl = new MatsBrokerMonitorBroadcastAndControl( matsBrokerMonitor, matsFactory); matsFactory.getFactoryConfig().installPlugin(broadcastAndControl); return broadcastAndControl; } private Consumer _eventUpdateListener; private MatsEndpoint _commandEndpoint; // ----- IMPLEMENTATION: MatsPlugin MatsBrokerMonitorBroadcastAndControl ----- @Override public void start(MatsFactory matsFactory) { // Start the MatsBrokerMonitor, as per contract in JavaDoc. _matsBrokerMonitor.start(); // :: Create the MatsBrokerMonitor UpdateEvent listener MatsInitiator matsInitiator = matsFactory.getDefaultInitiator(); _eventUpdateListener = updateEvent -> { if (updateEvent.isUpdateEventOriginatedOnThisNode()) { log.info("Got UpdateEvent from MBM originating from this MBM/host (fullUpdate:[" + updateEvent .isFullUpdate() + "]) - broadcasting to [" + BROADCAST_UPDATE_EVENT_TOPIC_ENDPOINT_ID + "]."); BroadcastUpdateEventDto dto = BroadcastUpdateEventDto.of(updateEvent); // Send the UpdateEvent to the topic endpoint matsInitiator.initiateUnchecked(init -> init .traceId("MatsBrokerMonitorBroadcastUpdate:" + Long.toString(Math.abs(ThreadLocalRandom.current().nextLong()), 36)) .from("MatsBrokerMonitorBroadcaster") .setTraceProperty(SUPPRESS_LOGGING_TRACE_PROPERTY_KEY, Boolean.TRUE) .to(BROADCAST_UPDATE_EVENT_TOPIC_ENDPOINT_ID) .publish(dto)); } else { log.debug("Got UpdateEvent from MBM which is NOT originating from this MBM/host! Will NOT broadcast."); } }; // .. register it _matsBrokerMonitor.registerListener(_eventUpdateListener); // :: Create the Command listener // On the off chance (i.e. only in the TestServer!) that another MatsBrokerMonitor command listener has already // been installed on this MatsFactory, we do not need to install one more. if (matsFactory.getEndpoint(MATSBROKERMONITOR_CONTROL).isEmpty()) { _commandEndpoint = matsFactory.terminator(MATSBROKERMONITOR_CONTROL, void.class, MatsBrokerMonitorCommandDto.class, (ctx, state, command) -> { // :: Is this FORCE_UPDATE or FORCE_UPDATE_FULL command? boolean fullUpdate = MatsBrokerMonitorCommandDto.FORCE_UPDATE_FULL.equals(command.getMethod()); if (fullUpdate || MatsBrokerMonitorCommandDto.FORCE_UPDATE.equals(command.getMethod())) { _matsBrokerMonitor.forceUpdate(command.getCorrelationId(), fullUpdate); } }); log.info("Added Endpoint for commands [" + MATSBROKERMONITOR_CONTROL + "]."); } else { _commandEndpoint = null; log.info("Already an Endpoint for commands installed [" + MATSBROKERMONITOR_CONTROL + "] on this MatsFactory, can't install one more, ignoring."); } } @Override public void preStop() { // Remove the command endpoint, just to be clean. if (_commandEndpoint != null) { _commandEndpoint.remove(15_000); _commandEndpoint = null; } // Remove us as listener from MatsBrokerMonitor _matsBrokerMonitor.removeListener(_eventUpdateListener); // .. and close the MatsBrokerMonitor, as per contract in JavaDoc. _matsBrokerMonitor.close(); } // TODO: Remove ASAP, once users have removed their call. Latest 2025. @Override public void close() { log.error("DO NOT INVOKE THIS METHOD!", new Exception("This method is deprecated -" + " the MatsFactory will handle it, by invoking preStop() and stop().")); } private MatsBrokerMonitorBroadcastAndControl(MatsBrokerMonitor matsBrokerMonitor, MatsFactory matsFactory) { _matsBrokerMonitor = matsBrokerMonitor; } /** * NOTE: THIS IS COPIED OVER TO MatsBrokerMonitorBroadcastReceiver *

* UpdateEvent DTO from MatsBrokerMonitor, which is sent to SubscriptionTerminator ("topic") EndpointId * {@link #BROADCAST_UPDATE_EVENT_TOPIC_ENDPOINT_ID}. */ private static class BroadcastUpdateEventDto implements UpdateEvent { private long suts; private String cid; // nullable private boolean fu; private BrokerInfoDto bi; // nullable private List ds; public BroadcastUpdateEventDto() { /* need no-args constructor for deserializing with Jackson */ } public static BroadcastUpdateEventDto of(UpdateEvent updateEvent) { NavigableMap eventDestinations = updateEvent.getEventDestinations(); ArrayList destinationDtos = new ArrayList<>(eventDestinations.size()); for (MatsBrokerDestination dest : eventDestinations.values()) { destinationDtos.add(MatsBrokerDestinationDto.of(dest)); } BrokerInfoDto brokerInfoDto = null; if (updateEvent.getBrokerInfo().isPresent()) { brokerInfoDto = BrokerInfoDto.of(updateEvent.getBrokerInfo().get()); } return new BroadcastUpdateEventDto(updateEvent.isFullUpdate(), updateEvent.getStatisticsUpdateMillis(), updateEvent.getCorrelationId().orElse(null), brokerInfoDto, destinationDtos); } public BroadcastUpdateEventDto(boolean fullUpdate, long statisticsUpdateMillis, String correlationId, BrokerInfoDto brokerInfo, List destinations) { this.suts = statisticsUpdateMillis; this.fu = fullUpdate; this.cid = correlationId; this.bi = brokerInfo; this.ds = destinations; } public boolean isFullUpdate() { return fu; } @Override public boolean isUpdateEventOriginatedOnThisNode() { return false; } @Override public Optional getBrokerInfo() { return Optional.ofNullable(bi); } @Override public long getStatisticsUpdateMillis() { return suts; } public Optional getCorrelationId() { return Optional.ofNullable(cid); } @Override public NavigableMap getEventDestinations() { TreeMap ret = new TreeMap<>(); for (MatsBrokerDestination dest : ds) { ret.put(dest.getFqDestinationName(), dest); } return ret; } } /** * NOTE: THIS IS COPIED OVER TO MatsBrokerMonitorBroadcastReceiver *

* "Command object", which can be sent to Endpoint {@link #MATSBROKERMONITOR_CONTROL}. */ private static class MatsBrokerMonitorCommandDto { /** * Can be {@link #FORCE_UPDATE} or {@link #FORCE_UPDATE_FULL} */ private String m; private String cid; public static String FORCE_UPDATE = "forceUpdate"; public static String FORCE_UPDATE_FULL = "forceUpdateFull"; public static MatsBrokerMonitorCommandDto forceUpdate(String correlationId, boolean full) { return new MatsBrokerMonitorCommandDto(correlationId, full ? FORCE_UPDATE_FULL : FORCE_UPDATE); } private MatsBrokerMonitorCommandDto() { /* need no-args constructor for deserializing with Jackson */ } private MatsBrokerMonitorCommandDto(String correlationId, String method) { this.m = method; this.cid = correlationId; } public String getMethod() { return m; } public String getCorrelationId() { return cid; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy