ch.qos.logback.core.spi.AbstractComponentTracker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of virtdata-lib-realer Show documentation
Show all versions of virtdata-lib-realer Show documentation
With inspiration from other libraries
/**
* 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 + ")";
}
}
}