1
2
3
4
5
6
7
8
9
10 package ch.qos.logback.core.sift;
11
12 import java.util.HashMap;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Map;
16
17 import ch.qos.logback.core.Appender;
18
19
20
21
22
23
24 public class AppenderTrackerImpl<E> implements AppenderTracker<E> {
25
26 Map<String, Entry> map = new HashMap<String, Entry>();
27
28 Entry head;
29 Entry tail;
30
31 long lastCheck = 0;
32
33 AppenderTrackerImpl() {
34 head = new Entry(null, null, 0);
35 tail = head;
36 }
37
38
39 public synchronized void put(String key, Appender<E> value, long timestamp) {
40 Entry entry = map.get(key);
41 if (entry == null) {
42 entry = new Entry(key, value, timestamp);
43 map.put(key, entry);
44 }
45 moveToTail(entry);
46 }
47
48 public synchronized Appender<E> get(String key, long timestamp) {
49 Entry existing = map.get(key);
50 if (existing == null) {
51 return null;
52 } else {
53 existing.setTimestamp(timestamp);
54 moveToTail(existing);
55 return existing.value;
56 }
57 }
58
59
60 public synchronized void stopStaleAppenders(long now) {
61 if (lastCheck + MILLIS_IN_ONE_SECOND > now) {
62 return;
63 }
64 lastCheck = now;
65 while (head.value != null && isEntryStale(head,now)) {
66 Appender appender = head.value;
67
68 appender.stop();
69 removeHead();
70 }
71 }
72
73 public List<String> keyList() {
74 List<String> result = new LinkedList<String>();
75 Entry e = head;
76 while (e != tail) {
77 result.add(e.key);
78 e = e.next;
79 }
80 return result;
81 }
82
83
84 final private boolean isEntryStale(Entry entry, long now) {
85 return ((entry.timestamp + THRESHOLD) < now);
86 }
87
88
89 private void removeHead() {
90
91 map.remove(head.key);
92 head = head.next;
93 head.prev = null;
94 }
95
96 private void moveToTail(Entry e) {
97 rearrangePreexistingLinks(e);
98 rearrangeTailLinks(e);
99 }
100
101 private void rearrangePreexistingLinks(Entry e) {
102 if (e.prev != null) {
103 e.prev.next = e.next;
104 }
105 if (e.next != null) {
106 e.next.prev = e.prev;
107 }
108 if (head == e) {
109 head = e.next;
110 }
111 }
112
113 private void rearrangeTailLinks(Entry e) {
114 if (head == tail) {
115 head = e;
116 }
117 Entry preTail = tail.prev;
118 if (preTail != null) {
119 preTail.next = e;
120 }
121 e.prev = preTail;
122 e.next = tail;
123 tail.prev = e;
124 }
125
126 public void dump() {
127 Entry e = head;
128 System.out.print("N:");
129 while (e != null) {
130
131 System.out.print(e.key + ", ");
132 e = e.next;
133 }
134 System.out.println();
135 }
136
137
138
139 public List<Appender<E>> valueList() {
140 List<Appender<E>> result = new LinkedList<Appender<E>>();
141 Entry e = head;
142 while (e != tail) {
143 result.add(e.value);
144 e = e.next;
145 }
146 return result;
147 }
148
149
150 private class Entry {
151 Entry next;
152 Entry prev;
153
154 String key;
155 Appender<E> value;
156 long timestamp;
157
158 Entry(String k, Appender<E> v, long timestamp) {
159 this.key = k;
160 this.value = v;
161 this.timestamp = timestamp;
162 }
163
164 public long getTimestamp() {
165 return timestamp;
166 }
167
168 public void setTimestamp(long timestamp) {
169 this.timestamp = timestamp;
170 }
171
172 @Override
173 public int hashCode() {
174 final int prime = 31;
175 int result = 1;
176 result = prime * result + ((key == null) ? 0 : key.hashCode());
177 return result;
178 }
179
180 @Override
181 public boolean equals(Object obj) {
182 if (this == obj)
183 return true;
184 if (obj == null)
185 return false;
186 if (getClass() != obj.getClass())
187 return false;
188 final Entry other = (Entry) obj;
189 if (key == null) {
190 if (other.key != null)
191 return false;
192 } else if (!key.equals(other.key))
193 return false;
194 if (value == null) {
195 if (other.value != null)
196 return false;
197 } else if (!value.equals(other.value))
198 return false;
199 return true;
200 }
201
202 @Override
203 public String toString() {
204 return "(" + key + ", " + value + ")";
205 }
206 }
207 }