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

com.stackify.api.common.error.ErrorCounter Maven / Gradle / Ivy

There is a newer version: 4.0.3
Show newest version
/*
 * ErrorCounter.java
 * Copyright 2014 Stackify
 */
package com.stackify.api.common.error;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.stackify.api.ErrorItem;
import com.stackify.api.StackifyError;
import com.stackify.api.common.codec.MessageDigests;

/**
 * ErrorCounter
 * @author Eric Martin
 */
public class ErrorCounter {
	
    /**
     * Map from
     *     MD5(--)
     * to
     *     Unix epoch minute, error count for that minute
     */
    private final Map errorCounter = new HashMap();

    /**
     * Unix epoch minute and error count for that minute
     * 
     * @author Eric Martin
     */
    protected static class MinuteCounter {

    	/**
    	 * Unix epoch minute
    	 */
    	private final long epochMinute;
    	
    	/**
    	 * Error count for that minute
    	 */
    	private final int errorCount;

    	/**
    	 * Constructs a new minute counter for the specified minute
    	 * @param epochMinute Unix epoch minute
    	 * @return A new minute counter for the specified minute
    	 */
    	public static MinuteCounter newMinuteCounter(final long epochMinute) {
    		return new MinuteCounter(epochMinute, 1);
    	}
    	
    	/**
    	 * Constructs a new minute counter from the existing counter with the count incremented
    	 * @param counter Error count for that minute
    	 * @return A new minute counter from the existing counter with the count incremented
    	 */
    	public static MinuteCounter incrementCounter(final MinuteCounter counter) {
    		return new MinuteCounter(counter.epochMinute, counter.errorCount + 1);
    	}
    	
    	/**
    	 * Private constructor
    	 * @param epochMinute Unix epoch minute
    	 * @param errorCount Error count for that minute
    	 */
    	private MinuteCounter(final long epochMinute, final int errorCount) {
    	    this.epochMinute = epochMinute;
    	    this.errorCount = errorCount;
    	}
    	
    	/**
    	 * @return the epochMinute
    	 */
    	public long getEpochMinute() {
    		return epochMinute;
    	}

    	/**
    	 * @return the errorCount
    	 */
    	public int getErrorCount() {
    		return errorCount;
    	}
    }
    
    /**
     * Gets the base error (the last error in the causal chain)
     * @param error The error
     * @return The inner most error
     */
    public static ErrorItem getBaseError(final StackifyError error) {
		if (error == null) {
			throw new NullPointerException("StackifyError is null");
		}

		ErrorItem errorItem = error.getError();

        if (errorItem != null) {
            while (errorItem.getInnerError() != null) {
                errorItem = errorItem.getInnerError();
            }
        }

        return errorItem;
    }
    
    /**
     * Generates a unique key based on the error. The key will be an MD5 hash of the type, type code, and method.
     * @param errorItem The error item
     * @return The unique key for the error
     */
    public static String getUniqueKey(final ErrorItem errorItem) {
		if (errorItem == null) {
			throw new NullPointerException("ErrorItem is null");
		}
		
		String type = errorItem.getErrorType();
    	String typeCode = errorItem.getErrorTypeCode();
    	String method = errorItem.getSourceMethod();

    	String uniqueKey = String.format("%s-%s-%s", type, typeCode, method);
    	
    	return MessageDigests.md5Hex(uniqueKey);
    }
    
    /**
     * Increments the counter for this error in the epoch minute specified
     * @param error The error
     * @param epochMinute The epoch minute
     * @return The count for the error after it has been incremented
     */
    public int incrementCounter(final StackifyError error, long epochMinute) {
		if (error == null) {
			throw new NullPointerException("StackifyError is null");
		}

        ErrorItem baseError = getBaseError(error);
    	String uniqueKey = getUniqueKey(baseError);

        // get the counter for this error
    	
    	int count = 0;

        if (errorCounter.containsKey(uniqueKey)) {
        	
            // counter exists

        	MinuteCounter counter = errorCounter.get(uniqueKey);

            if (counter.getEpochMinute() == epochMinute) {
                // counter exists for this current minute
                // increment the counter
            	MinuteCounter incCounter = MinuteCounter.incrementCounter(counter);
            	errorCounter.put(uniqueKey, incCounter);
            	count = incCounter.getErrorCount();
            } else {
                // counter did not exist for this minute
            	// overwrite the entry with a new one
            	MinuteCounter newCounter = MinuteCounter.newMinuteCounter(epochMinute);
            	errorCounter.put(uniqueKey, newCounter);
            	count = newCounter.getErrorCount();
            }
        } else {
            // counter did not exist so create a new one
        	MinuteCounter newCounter = MinuteCounter.newMinuteCounter(epochMinute);
        	errorCounter.put(uniqueKey, newCounter);
        	count = newCounter.getErrorCount();
        }
        
        return count;
    }
    
    /**
     * Purges the errorCounter map of expired entries
     * @param epochMinute The current time
     */
    public void purgeCounters(final long epochMinute)
    {
    	for (Iterator> it = errorCounter.entrySet().iterator(); it.hasNext(); ) {
    		Map.Entry entry = it.next();
    		
    		if (entry.getValue().getEpochMinute() < epochMinute) {
    			it.remove();
    		}
    	}
    }	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy