001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.spi; 015 016import ch.qos.logback.core.CoreConstants; 017import ch.qos.logback.core.helpers.CyclicBuffer; 018 019import java.util.*; 020 021/** 022 * Another tracker implementtion for testing purposes only. 023 * 024 * @author Ceki Gülcü 025 */ 026public class CyclicBufferTrackerT<E> implements ComponentTracker<CyclicBuffer<E>> { 027 028 int bufferSize = CyclicBufferTracker.DEFAULT_BUFFER_SIZE; 029 int maxComponents = CyclicBufferTracker.DEFAULT_NUMBER_OF_BUFFERS; 030 031 List<TEntry<E>> liveList = new LinkedList<TEntry<E>>(); 032 List<TEntry<E>> lingererList = new LinkedList<TEntry<E>>(); 033 034 long lastCheck = 0; 035 036 private TEntry<E> getEntry(List<TEntry<E>> list, String k) { 037 for (int i = 0; i < list.size(); i++) { 038 TEntry<E> te = list.get(i); 039 if (te.key.equals(k)) { 040 return te; 041 } 042 } 043 return null; 044 } 045 046 private TEntry<E> getFromEitherList(String key) { 047 TEntry<E> entry = getEntry(liveList, key); 048 if (entry != null) 049 return entry; 050 else { 051 return getEntry(lingererList, key); 052 } 053 } 054 055 private List<String> keysAsOrderedList(List<TEntry<E>> list) { 056 Collections.sort(list); 057 List<String> result = new LinkedList<String>(); 058 for (int i = 0; i < list.size(); i++) { 059 TEntry<E> te = list.get(i); 060 result.add(te.key); 061 } 062 return result; 063 } 064 065 List<String> liveKeysAsOrderedList() { 066 return keysAsOrderedList(liveList); 067 } 068 069 List<String> lingererKeysAsOrderedList() { 070 return keysAsOrderedList(lingererList); 071 } 072 073 public Set<String> allKeys() { 074 HashSet<String> allKeys = new HashSet<String>(); 075 for (TEntry<E> e : liveList) 076 allKeys.add(e.key); 077 for (TEntry<E> e : lingererList) 078 allKeys.add(e.key); 079 return allKeys; 080 } 081 082 public Collection<CyclicBuffer<E>> allComponents() { 083 List<CyclicBuffer<E>> allComponents = new ArrayList<CyclicBuffer<E>>(); 084 for (TEntry<E> e : liveList) 085 allComponents.add(e.value); 086 for (TEntry<E> e : lingererList) 087 allComponents.add(e.value); 088 089 return allComponents; 090 } 091 092 public CyclicBuffer<E> find(String key) { 093 TEntry<E> te = getFromEitherList(key); 094 if (te == null) 095 return null; 096 else 097 return te.value; 098 } 099 100 public CyclicBuffer<E> getOrCreate(String key, long timestamp) { 101 TEntry<E> te = getFromEitherList(key); 102 if (te == null) { 103 CyclicBuffer<E> cb = new CyclicBuffer<E>(bufferSize); 104 te = new TEntry<E>(key, cb, timestamp); 105 liveList.add(te); 106 if (liveList.size() > maxComponents) { 107 Collections.sort(liveList); 108 liveList.remove(0); 109 } 110 } else { 111 te.timestamp = timestamp; 112 Collections.sort(liveList); 113 } 114 return te.value; 115 } 116 117 public void endOfLife(String k) { 118 TEntry<E> te = null; 119 boolean found = false; 120 for (int i = 0; i < liveList.size(); i++) { 121 te = liveList.get(i); 122 if (te.key.equals(k)) { 123 liveList.remove(i); 124 found = true; 125 break; 126 } 127 } 128 if (found) { 129 lingererList.add(te); 130 } 131 } 132 133 private boolean isEntryStale(TEntry<E> entry, long now) { 134 return ((entry.timestamp + DEFAULT_TIMEOUT) < now); 135 } 136 137 private boolean isEntryDoneLingering(TEntry<E> tEntry, long now) { 138 return ((tEntry.timestamp + AbstractComponentTracker.LINGERING_TIMEOUT) < now); 139 } 140 141 public void removeStaleComponents(long now) { 142 if (isTooSoonForRemovalIteration(now)) 143 return; 144 // both list should be sorted before removal attempts 145 Collections.sort(liveList); 146 Collections.sort(lingererList); 147 removeComponentsInExcessFromMainList(); 148 removeStaleComponentsFromMainList(now); 149 removeStaleComponentsFromLingerersList(now); 150 } 151 152 private void removeComponentsInExcessFromMainList() { 153 while (liveList.size() > maxComponents) { 154 liveList.remove(0); 155 } 156 } 157 158 private void removeStaleComponentsFromMainList(long now) { 159 while (liveList.size() != 0 && isEntryStale(liveList.get(0), now)) { 160 liveList.remove(0); 161 } 162 } 163 164 private void removeStaleComponentsFromLingerersList(long now) { 165 while (lingererList.size() != 0 && isEntryDoneLingering(lingererList.get(0), now)) { 166 lingererList.remove(0); 167 } 168 } 169 170 private boolean isTooSoonForRemovalIteration(long now) { 171 if (lastCheck + CoreConstants.MILLIS_IN_ONE_SECOND > now) { 172 return true; 173 } 174 lastCheck = now; 175 return false; 176 } 177 178 public int getComponentCount() { 179 return liveList.size() + lingererList.size(); 180 } 181 182 // ================================================================== 183 184 private class TEntry<X> implements Comparable<TEntry<?>> { 185 186 String key; 187 CyclicBuffer<E> value; 188 long timestamp; 189 190 TEntry(String k, CyclicBuffer<E> v, long timestamp) { 191 this.key = k; 192 this.value = v; 193 this.timestamp = timestamp; 194 } 195 196 @Override 197 public int hashCode() { 198 final int prime = 31; 199 int result = 1; 200 result = prime * result + ((key == null) ? 0 : key.hashCode()); 201 return result; 202 } 203 204 public int compareTo(TEntry<?> o) { 205 if (!(o instanceof TEntry)) { 206 throw new IllegalArgumentException("arguments must be of type " + TEntry.class); 207 } 208 209 TEntry<?> other = (TEntry<?>) o; 210 if (timestamp > other.timestamp) { 211 return 1; 212 } 213 if (timestamp == other.timestamp) { 214 return 0; 215 } 216 return -1; 217 } 218 219 @Override 220 public boolean equals(Object obj) { 221 if (this == obj) 222 return true; 223 if (obj == null) 224 return false; 225 if (getClass() != obj.getClass()) 226 return false; 227 @SuppressWarnings("unchecked") 228 final TEntry<?> other = (TEntry<?>) obj; 229 if (key == null) { 230 if (other.key != null) 231 return false; 232 } else if (!key.equals(other.key)) 233 return false; 234 if (value == null) { 235 if (other.value != null) 236 return false; 237 } else if (!value.equals(other.value)) 238 return false; 239 return true; 240 } 241 242 @Override 243 public String toString() { 244 return "(" + key + ", " + value + ")"; 245 } 246 } 247}