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

com.distelli.monitor.impl.MonitorInfoImpl Maven / Gradle / Ivy

package com.distelli.monitor.impl;

import com.distelli.monitor.MonitorInfo;
import java.util.Map;
import java.util.HashMap;
import com.distelli.utils.CompactUUID;
import java.util.Collections;
import java.lang.management.ManagementFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MonitorInfoImpl implements MonitorInfo {
    private static final Logger LOG = LoggerFactory.getLogger(MonitorInfoImpl.class);
    // Persisted:
    private String monitorId;
    private String nodeName;
    private String version;
    private long heartbeat;

    // Transient:
    private boolean hasFailedHeartbeat;
    private Map runningThreads = new HashMap<>();
    private long lastHeartbeatMillis;
    private long maxTimeBetweenHeartbeat;

    public MonitorInfoImpl() {}
    public MonitorInfoImpl(String version, long maxTimeBetweenHeartbeat) {
        this.monitorId = CompactUUID.randomUUID().toString();
        this.hasFailedHeartbeat = false;
        this.nodeName = ManagementFactory.getRuntimeMXBean().getName();
        this.version = version;
        this.heartbeat = 1;
        this.lastHeartbeatMillis = milliTime();
        this.maxTimeBetweenHeartbeat = maxTimeBetweenHeartbeat;
    }

    @Override
    public String getMonitorId() {
        return monitorId;
    }

    @Override
    public synchronized boolean hasFailedHeartbeat() {
        if ( ! hasFailedHeartbeat && milliTime() - lastHeartbeatMillis > maxTimeBetweenHeartbeat ) {
            LOG.error("Forcing heartbeat failure due to max time between heartbeat");
            forceHeartbeatFailure();
        }
        return hasFailedHeartbeat;
    }

    @Override
    public String getNodeName() {
        return nodeName;
    }

    @Override
    public String getVersion() {
        return version;
    }

    @Override
    public synchronized long getHeartbeat() {
        return heartbeat;
    }

    @Override
    public synchronized void forceHeartbeatFailure() {
        hasFailedHeartbeat = true;
    }

    public synchronized boolean isRunningInMonitoredThread() {
        AtomicInteger count = runningThreads.get(Thread.currentThread());
        return null != count && count.get() > 0;
    }

    public synchronized void captureRunningThread() {
        Thread thread = Thread.currentThread();
        AtomicInteger count = runningThreads.get(thread);
        if ( null == count ) {
            count = new AtomicInteger(0);
            runningThreads.put(thread, count);
        }
        count.incrementAndGet();
    }

    // Returns true if the count for this thread drops to zero:
    public synchronized boolean releaseRunningThread() {
        Thread thread = Thread.currentThread();
        AtomicInteger count = runningThreads.get(thread);
        if ( null == count || 0 == count.decrementAndGet() ) {
            runningThreads.remove(thread);
            if ( runningThreads.isEmpty() ) notifyAll();
            return true;
        }
        return false;
    }

    public synchronized boolean heartbeatWasPerformed() {
        lastHeartbeatMillis = milliTime();
        heartbeat++;
        return hasFailedHeartbeat;
    }

    public synchronized long getLastHeartbeatMillis() {
        return lastHeartbeatMillis;
    }

    private static long milliTime() {
        return TimeUnit.MILLISECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS);
    }

    public synchronized String dumpThreads() {
        StringBuilder sb = new StringBuilder();
        for ( Thread thread : runningThreads.keySet() ) {
            sb.append(thread.getName()).append(":\n");
            for ( StackTraceElement ste : thread.getStackTrace() ) {
                sb.append("\t").append(ste.toString()).append("\n");
            }
        }
        return sb.toString();
    }

    // Returns true if all threads got shutdown in the millisWaitMax time.
    public synchronized boolean interruptAndWaitForRunningThreads(long millisWaitMax, boolean mayInterruptIfRunning) {
        if ( mayInterruptIfRunning ) {
            Thread cur = Thread.currentThread();
            for ( Thread thread : runningThreads.keySet() ) {
                if ( cur == thread ) {
                    throw new IllegalStateException("interruptAndWaitForRunningThreads() called within a monitor()");
                }
                thread.interrupt();
            }
        }
        long start = milliTime();
        while ( ! runningThreads.isEmpty() ) {
            long now = milliTime();
            long max = millisWaitMax - (now - start);
            if ( max <= 0 ) return false;
            try {
                wait(max);
            } catch ( InterruptedException ex ) {
                return false;
            }
        }
        return true;
    }

    @Override
    public String toString() {
        return "MonitorInfo{"
            +"monitorId="+monitorId
            +",nodeName="+nodeName
            +",heartbeat="+heartbeat
            +",hasFailedHeartbeat="+hasFailedHeartbeat
            +",lastHeartbeatMillis="+lastHeartbeatMillis
            +",maxTimeBetweenHeartbeat="+maxTimeBetweenHeartbeat
            +",runningThreads="+runningThreads
            +"}";
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy