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

ch.qos.logback.core.spi.AbstractComponentTracker Maven / Gradle / Ivy

There is a newer version: 2.12.15
Show newest version
/**
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */
package ch.qos.logback.core.spi;

import ch.qos.logback.core.CoreConstants;

import java.util.*;

/**
 * An abstract implementation of the ComponentTracker interface. Derived classes must implement
 * {@link #buildComponent(String)}, {@link #processPriorToRemoval(Object)}, and {@link #isComponentStale(Object)}
 * methods as appropriate for their component type.
 *
 * @param  component type
 *
 * @author Tommy Becker
 * @author Ceki Gulcu
 * @author David Roussel
 */
abstract public class AbstractComponentTracker implements ComponentTracker {
    private static final boolean ACCESS_ORDERED = true;

    // Components in lingering state last 10 seconds
    final public static long LINGERING_TIMEOUT = 10 * CoreConstants.MILLIS_IN_ONE_SECOND;

    /**
     * The minimum amount of time that has to elapse between successive removal iterations.
     */
    final public static long WAIT_BETWEEN_SUCCESSIVE_REMOVAL_ITERATIONS = CoreConstants.MILLIS_IN_ONE_SECOND;

    protected int maxComponents = DEFAULT_MAX_COMPONENTS;
    protected long timeout = DEFAULT_TIMEOUT;

    // an access ordered map. Least recently accessed element will be removed after a 'timeout'
    LinkedHashMap> liveMap = new LinkedHashMap>(32, .75f, ACCESS_ORDERED);

    // an access ordered map. Least recently accessed element will be removed after LINGERING_TIMEOUT
    LinkedHashMap> lingerersMap = new LinkedHashMap>(16, .75f, ACCESS_ORDERED);
    long lastCheck = 0;

    /**
     * Stop or clean the component.
     *
     * @param component
     */
    abstract protected void processPriorToRemoval(C component);

    /**
     * Build a component based on the key.
     *
     * @param key
     * @return
     */
    abstract protected C buildComponent(String key);

    /**
     * Components can declare themselves stale. Such components may be
     * removed before they time out.
     *
     * @param c
     * @return
     */
    protected abstract boolean isComponentStale(C c);

    public int getComponentCount() {
        return liveMap.size() + lingerersMap.size();
    }

    /**
     * Get an entry from the liveMap, if not found search the lingerersMap.
     *
     * @param key
     * @return
     */
    private Entry getFromEitherMap(String key) {
        Entry entry = liveMap.get(key);
        if (entry != null)
            return entry;
        else {
            return lingerersMap.get(key);
        }
    }

    /**
     * {@inheritDoc}
     *
     * 

Note that this method is synchronized.

* * @param key {@inheritDoc} * @return {@inheritDoc} * */ public synchronized C find(String key) { Entry entry = getFromEitherMap(key); if (entry == null) return null; else return entry.component; } /** * {@inheritDoc} * *

Note that this method is atomic, i.e. synchronized.

* * @param key {@inheritDoc} * @param timestamp {@inheritDoc} * @return {@inheritDoc} */ public synchronized C getOrCreate(String key, long timestamp) { Entry entry = getFromEitherMap(key); if (entry == null) { C c = buildComponent(key); entry = new Entry(key, c, timestamp); // new entries go into the main map liveMap.put(key, entry); } else { entry.setTimestamp(timestamp); } return entry.component; } /** * Mark component identified by 'key' as having reached its end-of-life. * * @param key */ public void endOfLife(String key) { Entry entry = liveMap.remove(key); if (entry == null) return; lingerersMap.put(key, entry); } /** * Clear (and detach) components which are stale. Components which have not * been accessed for more than a user-specified duration are deemed stale. * * @param now */ public synchronized void removeStaleComponents(long now) { if (isTooSoonForRemovalIteration(now)) return; removeExcedentComponents(); removeStaleComponentsFromMainMap(now); removeStaleComponentsFromLingerersMap(now); } private void removeExcedentComponents() { genericStaleComponentRemover(liveMap, 0, byExcedent); } private void removeStaleComponentsFromMainMap(long now) { genericStaleComponentRemover(liveMap, now, byTimeout); } private void removeStaleComponentsFromLingerersMap(long now) { genericStaleComponentRemover(lingerersMap, now, byLingering); } private void genericStaleComponentRemover(LinkedHashMap> map, long now, RemovalPredicator removalPredicator) { Iterator>> iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry> mapEntry = iter.next(); Entry entry = mapEntry.getValue(); if (removalPredicator.isSlatedForRemoval(entry, now)) { iter.remove(); C c = entry.component; processPriorToRemoval(c); } else { break; } } } private RemovalPredicator byExcedent = new RemovalPredicator() { public boolean isSlatedForRemoval(Entry entry, long timestamp) { return (liveMap.size() > maxComponents); } }; private RemovalPredicator byTimeout = new RemovalPredicator() { public boolean isSlatedForRemoval(Entry entry, long timestamp) { return isEntryStale(entry, timestamp); } }; private RemovalPredicator byLingering = new RemovalPredicator() { public boolean isSlatedForRemoval(Entry entry, long timestamp) { return isEntryDoneLingering(entry, timestamp); } }; private boolean isTooSoonForRemovalIteration(long now) { if (lastCheck + WAIT_BETWEEN_SUCCESSIVE_REMOVAL_ITERATIONS > now) { return true; } lastCheck = now; return false; } private boolean isEntryStale(Entry entry, long now) { // stopped or improperly started appenders are considered stale // see also http://jira.qos.ch/browse/LBCLASSIC-316 C c = entry.component; if (isComponentStale(c)) return true; return ((entry.timestamp + timeout) < now); } private boolean isEntryDoneLingering(Entry entry, long now) { return ((entry.timestamp + LINGERING_TIMEOUT) < now); } public Set allKeys() { HashSet allKeys = new HashSet(liveMap.keySet()); allKeys.addAll(lingerersMap.keySet()); return allKeys; } public Collection allComponents() { List allComponents = new ArrayList(); for (Entry e : liveMap.values()) allComponents.add(e.component); for (Entry e : lingerersMap.values()) allComponents.add(e.component); return allComponents; } public long getTimeout() { return timeout; } public void setTimeout(long timeout) { this.timeout = timeout; } public int getMaxComponents() { return maxComponents; } public void setMaxComponents(int maxComponents) { this.maxComponents = maxComponents; } // ================================================================ private interface RemovalPredicator { boolean isSlatedForRemoval(Entry entry, long timestamp); } // ================================================================ private static class Entry { String key; C component; long timestamp; Entry(String k, C c, long timestamp) { this.key = k; this.component = c; this.timestamp = timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } @Override public int hashCode() { return key.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; @SuppressWarnings("unchecked") final Entry other = (Entry) obj; if (key == null) { if (other.key != null) return false; } else if (!key.equals(other.key)) return false; if (component == null) { if (other.component != null) return false; } else if (!component.equals(other.component)) return false; return true; } @Override public String toString() { return "(" + key + ", " + component + ")"; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy