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

io.mats3.matsbrokermonitor.broadcastreceiver.MatsBrokerMonitorBroadcastReceiver Maven / Gradle / Ivy

There is a newer version: 1.0.13-2024-06-17
Show newest version
package io.mats3.matsbrokermonitor.broadcastreceiver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
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.MatsStage;
import io.mats3.MatsStage.StageConfig;
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.MatsBrokerDestination.StageDestinationType;
import io.mats3.matsbrokermonitor.api.MatsBrokerMonitor.MatsBrokerDestinationDto;
import io.mats3.matsbrokermonitor.api.MatsBrokerMonitor.UpdateEvent;

/**
 * @author Endre Stølsvik 2022-11-12 10:34 - http://stolsvik.com/, [email protected]
 */
public class MatsBrokerMonitorBroadcastReceiver implements MatsPlugin {
    private static final Logger log = LoggerFactory.getLogger(MatsBrokerMonitorBroadcastReceiver.class);

    /**
     * Copied from MatsBrokerMonitorBroadcastAndControl
     * 

* The EndpointId to which the update event is published. *

* Value is "mats.MatsBrokerMonitorBroadcastUpdate". */ private static final String BROADCAST_UPDATE_EVENT_TOPIC_ENDPOINT_ID = "mats.MatsBrokerMonitor.broadcastUpdate"; /** * Copied from MatsBrokerMonitorBroadcastAndControl *

* 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 accept that this won't be logged, as it will be annoying noise without much merit. */ private static final String SUPPRESS_LOGGING_ENDPOINT_ALLOWS_ATTRIBUTE_KEY = "mats.SuppressLoggingAllowed"; private MatsEndpoint _broadcastReceiver; private final MatsFactory _matsFactory; private final CopyOnWriteArrayList> _listeners = new CopyOnWriteArrayList<>(); public static MatsBrokerMonitorBroadcastReceiver install(MatsFactory matsFactory) { MatsBrokerMonitorBroadcastReceiver broadcastReceiver = new MatsBrokerMonitorBroadcastReceiver(matsFactory); matsFactory.getFactoryConfig().installPlugin(broadcastReceiver); return broadcastReceiver; } public void forceUpdate(String correlationId, boolean full) { _matsFactory.getDefaultInitiator().initiateUnchecked(init -> init .traceId("MatsBrokerMonitorBroadcastReceiver.forceUpdate:" + Long.toString(Math.abs(ThreadLocalRandom.current().nextLong()), 36)) .from("MatsBrokerMonitorBroadcastReceiver.forceUpdate") .to(MATSBROKERMONITOR_CONTROL) .send(MatsBrokerMonitorCommandDto.forceUpdate(correlationId, full))); } public void registerListener(Consumer listener) { _listeners.add(listener); } public void removeListener(Consumer listener) { _listeners.remove(listener); } // ----- IMPLEMENTATION: MatsPlugin MatsBrokerMonitorBroadcastReceiver ----- private MatsBrokerMonitorBroadcastReceiver(MatsFactory matsFactory) { _matsFactory = matsFactory; } @Override public void start(MatsFactory matsFactory) { // :: Create the SubscriptionTerminator receiving the broadcast from MatsBrokerMonitorBroadcastAndControl _broadcastReceiver = matsFactory.subscriptionTerminator(BROADCAST_UPDATE_EVENT_TOPIC_ENDPOINT_ID, void.class, BroadcastUpdateEventDto.class, (ctx, state, updateEvent) -> { NavigableMap eventDestinations = updateEvent.getEventDestinations(); if (log.isDebugEnabled()) log.debug("Received Update: FullUpdate:[" + updateEvent.isFullUpdate() + "], CorrelationId:[" + updateEvent.getCorrelationId() + "], # of destinations:[" + eventDestinations.size() + "]."); // :: Move all MatsBrokerDestination to a Map with StageId as key, and then a Map with // StageDestinationType as key. Map> destMap = new HashMap<>(); for (MatsBrokerDestination dest : eventDestinations.values()) { if (dest.getMatsStageId().isPresent() && dest.getStageDestinationType().isPresent()) { Map stageMap = destMap .computeIfAbsent(dest.getMatsStageId().get(), __ -> new HashMap<>()); stageMap.put(dest.getStageDestinationType().get(), dest); if (log.isDebugEnabled()) log.debug(" \\- Received [" + dest.getStageDestinationType() .get() + "] info [" + dest.getNumberOfQueuedMessages() + " msgs] for stage [" + dest.getMatsStageId().get() + "]"); } } // :: For all Stages for all Endpoints in the MatsFactory, add the destination info as a set of // attributes on the StageConfig, using above maps. If we don't have info for a stage, we null it. List> endpoints = matsFactory.getEndpoints(); for (MatsEndpoint endpoint : endpoints) { List> stages = endpoint.getStages(); for (MatsStage stage : stages) { StageConfig stageConfig = stage.getStageConfig(); String stageId = stageConfig.getStageId(); Map typeMap = destMap.get(stageId); for (StageDestinationType enumV : StageDestinationType.values()) { // We want to set null if the destination is not present in the update. MatsBrokerDestination dest = typeMap != null ? typeMap.get(enumV) // might return null, which is correct. : null; stageConfig.setAttribute(enumV.getStageAttribute(), dest); stageConfig.setAttribute(enumV.getStageAttributeAge(), dest != null ? dest.getHeadMessageAgeMillis() : null); stageConfig.setAttribute(enumV.getStageAttributeSize(), dest != null ? dest.getNumberOfQueuedMessages() : null); } } } // :: Notify any listeners. for (Consumer listener : _listeners) { try { listener.accept(updateEvent); } catch (Throwable t) { log.error("The listener of class [" + listener.getClass().getName() + "] threw when being invoked. Ignoring.", t); } } }); // :: We don't want this to be logged, as it will be annoying noise without much merit. // Allow for log suppression for this SubscriptionTerminator _broadcastReceiver.getEndpointConfig().setAttribute(SUPPRESS_LOGGING_ENDPOINT_ALLOWS_ATTRIBUTE_KEY, Boolean.TRUE); } @Override public void preStop() { // Remove and null the SubscriptionTerminator Endpoint from MatsFactory, just to be clean. _broadcastReceiver.remove(15_000); _broadcastReceiver = null; // No more listeners _listeners.clear(); } /** * NOTE: THIS IS COPIED OVER from MatsBrokerMonitorBroadcastAndControl. *

* 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; } @Override public String toString() { return "UpdateEventDto{" + "statisticsUpdateMillis=" + suts + ", correlationId='" + cid + '\'' + ", isFullUpdate=" + fu + ", brokerInfo=" + bi + ", eventDestinations=" + ds.size() + '}'; } } /** * NOTE: THIS IS COPIED OVER from MatsBrokerMonitorBroadcastAndControl. *

* "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