View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.sift;
15  
16  import java.util.HashMap;
17  import java.util.LinkedList;
18  import java.util.List;
19  import java.util.Map;
20  
21  import ch.qos.logback.core.Appender;
22  import ch.qos.logback.core.CoreConstants;
23  
24  /**
25   * Track appenders by a key. When an appender is not used for
26   * longer than THRESHOLD, stop it.
27   * @author Ceki Gulcu
28   */
29  public class AppenderTrackerImpl<E> implements AppenderTracker<E> {
30  
31    Map<String, Entry> map = new HashMap<String, Entry>();
32   
33    Entry head; // least recently used entries are towards the head
34    Entry tail; // most recently used entries are towards the tail
35  
36    long lastCheck = 0;
37  
38    AppenderTrackerImpl() {
39      head = new Entry(null, null, 0);
40      tail = head;
41    }
42  
43  
44    public synchronized void put(String key, Appender<E> value, long timestamp) {
45      Entry entry = map.get(key);
46      if (entry == null) {
47        entry = new Entry(key, value, timestamp);
48        map.put(key, entry);
49      }
50      moveToTail(entry);
51    }
52  
53    public synchronized Appender<E> get(String key, long timestamp) {
54      Entry existing = map.get(key);
55      if (existing == null) {
56        return null;
57      } else {
58        existing.setTimestamp(timestamp);
59        moveToTail(existing);
60        return existing.value;
61      }
62    }
63  
64    
65    public synchronized void stopStaleAppenders(long now) {
66      if (lastCheck + CoreConstants.MILLIS_IN_ONE_SECOND > now) {
67        return;
68      }
69      lastCheck = now;
70      while (head.value != null && isEntryStale(head,now)) {
71        Appender<E> appender = head.value;
72        appender.stop();
73        removeHead();
74      }
75    } 
76  
77    /**
78     * @since 0.9.19
79     * @param key
80     */
81    public synchronized void stopAndRemoveNow(String key) {
82      Entry e = head;
83      Entry found = null;
84      while (e != tail) {
85        if(key.equals(e.key)) {
86          found = e;
87          break;
88        }
89        e = e.next;
90      }
91      if(found != null) {
92        rearrangePreexistingLinks(e);
93        map.remove(key);
94        Appender<E> appender = e.value;
95        appender.stop();
96      }
97    }
98    
99    public List<String> keyList() {
100     List<String> result = new LinkedList<String>();
101     Entry e = head;
102     while (e != tail) {
103       result.add(e.key);
104       e = e.next;
105     }
106     return result;
107   }
108   
109   
110   final private boolean isEntryStale(Entry entry, long now) {
111     return ((entry.timestamp + THRESHOLD) < now);
112   }
113 
114   
115   private void removeHead() {
116     // System.out.println("RemoveHead called");
117     map.remove(head.key);
118     head = head.next;
119     head.prev = null;
120   }
121 
122   private void moveToTail(Entry e) {
123     rearrangePreexistingLinks(e);
124     rearrangeTailLinks(e);
125   }
126 
127   private void rearrangePreexistingLinks(Entry e) {
128     if (e.prev != null) {
129       e.prev.next = e.next;
130     }
131     if (e.next != null) {
132       e.next.prev = e.prev;
133     }
134     if (head == e) {
135       head = e.next;
136     }
137   }
138 
139   private void rearrangeTailLinks(Entry e) {
140     if (head == tail) {
141       head = e;
142     }
143     Entry preTail = tail.prev;
144     if (preTail != null) {
145       preTail.next = e;
146     }
147     e.prev = preTail;
148     e.next = tail;
149     tail.prev = e;
150   }
151 
152   public void dump() {
153     Entry e = head;
154     System.out.print("N:");
155     while (e != null) {
156       // System.out.print(e+"->");
157       System.out.print(e.key + ", ");
158       e = e.next;
159     }
160     System.out.println();
161   }
162 
163 
164 
165   public List<Appender<E>> valueList() {
166     List<Appender<E>> result = new LinkedList<Appender<E>>();
167     Entry e = head;
168     while (e != tail) {
169       result.add(e.value);
170       e = e.next;
171     }
172     return result;
173   }
174   
175   // ================================================================
176   private class Entry {
177     Entry next;
178     Entry prev;
179 
180     String key;
181     Appender<E> value;
182     long timestamp;
183 
184     Entry(String k, Appender<E> v, long timestamp) {
185       this.key = k;
186       this.value = v;
187       this.timestamp = timestamp;
188     }
189 
190 //    public long getTimestamp() {
191 //      return timestamp;
192 //    }
193 
194     public void setTimestamp(long timestamp) {
195       this.timestamp = timestamp;
196     }
197 
198     @Override
199     public int hashCode() {
200       final int prime = 31;
201       int result = 1;
202       result = prime * result + ((key == null) ? 0 : key.hashCode());
203       return result;
204     }
205 
206     @Override
207     public boolean equals(Object obj) {
208       if (this == obj)
209         return true;
210       if (obj == null)
211         return false;
212       if (getClass() != obj.getClass())
213         return false;
214       final Entry other = (Entry) obj;
215       if (key == null) {
216         if (other.key != null)
217           return false;
218       } else if (!key.equals(other.key))
219         return false;
220       if (value == null) {
221         if (other.value != null)
222           return false;
223       } else if (!value.equals(other.value))
224         return false;
225       return true;
226     }
227 
228     @Override
229     public String toString() {
230       return "(" + key + ", " + value + ")";
231     }
232   }
233 }