/** * 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 ch.qos.logback.core.helpers.CyclicBuffer; import java.util.*; /** * Another tracker implementtion for testing purposes only. * * @author Ceki Gülcü */ public class CyclicBufferTrackerT<E> implements ComponentTracker<CyclicBuffer<E>> { int bufferSize = CyclicBufferTracker.DEFAULT_BUFFER_SIZE; int maxComponents = CyclicBufferTracker.DEFAULT_NUMBER_OF_BUFFERS; List<TEntry<E>> liveList = new LinkedList<TEntry<E>>(); List<TEntry<E>> lingererList = new LinkedList<TEntry<E>>(); long lastCheck = 0; private TEntry<E> getEntry(List<TEntry<E>> list, String k) { for (int i = 0; i < list.size(); i++) { TEntry<E> te = list.get(i); if (te.key.equals(k)) { return te; } } return null; } private TEntry getFromEitherList(String key) { TEntry entry = getEntry(liveList, key); if (entry != null) return entry; else { return getEntry(lingererList, key); } } private List<String> keysAsOrderedList(List<TEntry<E>> list) { Collections.sort(list); List<String> result = new LinkedList<String>(); for (int i = 0; i < list.size(); i++) { TEntry<E> te = list.get(i); result.add(te.key); } return result; } List<String> liveKeysAsOrderedList() { return keysAsOrderedList(liveList); } List<String> lingererKeysAsOrderedList() { return keysAsOrderedList(lingererList); } public Set<String> allKeys() { HashSet<String> allKeys = new HashSet<String>(); for (TEntry e : liveList) allKeys.add(e.key); for (TEntry e : lingererList) allKeys.add(e.key); return allKeys; } public Collection<CyclicBuffer<E>> allComponents() { List<CyclicBuffer<E>> allComponents = new ArrayList<CyclicBuffer<E>>(); for (TEntry e : liveList) allComponents.add(e.value); for (TEntry e : lingererList) allComponents.add(e.value); return allComponents; } public CyclicBuffer<E> find(String key) { TEntry<E> te = getFromEitherList(key); if (te == null) return null; else return te.value; } public CyclicBuffer<E> getOrCreate(String key, long timestamp) { TEntry<E> te = getFromEitherList(key); if (te == null) { CyclicBuffer<E> cb = new CyclicBuffer<E>(bufferSize); te = new TEntry<E>(key, cb, timestamp); liveList.add(te); if (liveList.size() > maxComponents) { Collections.sort(liveList); liveList.remove(0); } } else { te.timestamp = timestamp; Collections.sort(liveList); } return te.value; } public void endOfLife(String k) { TEntry<E> te = null; boolean found = false; for (int i = 0; i < liveList.size(); i++) { te = liveList.get(i); if (te.key.equals(k)) { liveList.remove(i); found = true; break; } } if (found) { lingererList.add(te); } } private boolean isEntryStale(TEntry<E> entry, long now) { return ((entry.timestamp + DEFAULT_TIMEOUT) < now); } private boolean isEntryDoneLingering(TEntry<E> tEntry, long now) { return ((tEntry.timestamp + AbstractComponentTracker.LINGERING_TIMEOUT) < now); } public void removeStaleComponents(long now) { if (isTooSoonForRemovalIteration(now)) return; // both list should be sorted before removal attempts Collections.sort(liveList); Collections.sort(lingererList); removeComponentsInExcessFromMainList(); removeStaleComponentsFromMainList(now); removeStaleComponentsFromLingerersList(now); } private void removeComponentsInExcessFromMainList() { while (liveList.size() > maxComponents) { liveList.remove(0); } } private void removeStaleComponentsFromMainList(long now) { while (liveList.size() != 0 && isEntryStale(liveList.get(0), now)) { liveList.remove(0); } } private void removeStaleComponentsFromLingerersList(long now) { while (lingererList.size() != 0 && isEntryDoneLingering(lingererList.get(0), now)) { lingererList.remove(0); } } private boolean isTooSoonForRemovalIteration(long now) { if (lastCheck + CoreConstants.MILLIS_IN_ONE_SECOND > now) { return true; } lastCheck = now; return false; } public int getComponentCount() { return liveList.size() + lingererList.size(); } // ================================================================== private class TEntry<X> implements Comparable<TEntry<?>> { String key; CyclicBuffer<E> value; long timestamp; TEntry(String k, CyclicBuffer<E> v, long timestamp) { this.key = k; this.value = v; this.timestamp = timestamp; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((key == null) ? 0 : key.hashCode()); return result; } public int compareTo(TEntry<?> o) { if (!(o instanceof TEntry)) { throw new IllegalArgumentException("arguments must be of type " + TEntry.class); } TEntry<?> other = (TEntry<?>) o; if (timestamp > other.timestamp) { return 1; } if (timestamp == other.timestamp) { return 0; } return -1; } @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 TEntry<?> other = (TEntry<?>) obj; if (key == null) { if (other.key != null) return false; } else if (!key.equals(other.key)) return false; if (value == null) { if (other.value != null) return false; } else if (!value.equals(other.value)) return false; return true; } @Override public String toString() { return "(" + key + ", " + value + ")"; } } }