View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, 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;
15  
16  import java.util.ArrayList;
17  import java.util.List;
18  
19  import ch.qos.logback.core.helpers.CyclicBuffer;
20  import ch.qos.logback.core.spi.LogbackLock;
21  import ch.qos.logback.core.status.OnConsoleStatusListener;
22  import ch.qos.logback.core.status.Status;
23  import ch.qos.logback.core.status.StatusListener;
24  import ch.qos.logback.core.status.StatusManager;
25  
26  public class BasicStatusManager implements StatusManager {
27  
28      public static final int MAX_HEADER_COUNT = 150;
29      public static final int TAIL_SIZE = 150;
30  
31      int count = 0;
32  
33      // protected access was requested in http://jira.qos.ch/browse/LBCORE-36
34      final protected List<Status> statusList = new ArrayList<Status>();
35      final protected CyclicBuffer<Status> tailBuffer = new CyclicBuffer<Status>(TAIL_SIZE);
36      final protected LogbackLock statusListLock = new LogbackLock();
37  
38      int level = Status.INFO;
39  
40      // protected access was requested in http://jira.qos.ch/browse/LBCORE-36
41      final protected List<StatusListener> statusListenerList = new ArrayList<StatusListener>();
42      final protected LogbackLock statusListenerListLock = new LogbackLock();
43  
44      // Note on synchronization
45      // This class contains two separate locks statusListLock and
46      // statusListenerListLock guarding respectively the statusList+tailBuffer and
47      // statusListenerList fields. The locks are used internally
48      // without cycles. They are exposed to derived classes which should be careful
49      // not to create deadlock cycles.
50  
51      /**
52       * Add a new status object.
53       * 
54       * @param newStatus the status message to add
55       */
56      public void add(Status newStatus) {
57          // LBCORE-72: fire event before the count check
58          fireStatusAddEvent(newStatus);
59  
60          count++;
61          if (newStatus.getLevel() > level) {
62              level = newStatus.getLevel();
63          }
64  
65          synchronized (statusListLock) {
66              if (statusList.size() < MAX_HEADER_COUNT) {
67                  statusList.add(newStatus);
68              } else {
69                  tailBuffer.add(newStatus);
70              }
71          }
72  
73      }
74  
75      public List<Status> getCopyOfStatusList() {
76          synchronized (statusListLock) {
77              List<Status> tList = new ArrayList<Status>(statusList);
78              tList.addAll(tailBuffer.asList());
79              return tList;
80          }
81      }
82  
83      private void fireStatusAddEvent(Status status) {
84          synchronized (statusListenerListLock) {
85              for (StatusListener sl : statusListenerList) {
86                  sl.addStatusEvent(status);
87              }
88          }
89      }
90  
91      public void clear() {
92          synchronized (statusListLock) {
93              count = 0;
94              statusList.clear();
95              tailBuffer.clear();
96          }
97      }
98  
99      public int getLevel() {
100         return level;
101     }
102 
103     public int getCount() {
104         return count;
105     }
106 
107     /**
108      * This implementation does not allow duplicate installations of
109      * OnConsoleStatusListener
110      * 
111      * @param listener
112      */
113     public boolean add(StatusListener listener) {
114         synchronized (statusListenerListLock) {
115             if (listener instanceof OnConsoleStatusListener) {
116                 boolean alreadyPresent = checkForPresence(statusListenerList, listener.getClass());
117                 if (alreadyPresent)
118                     return false;
119             }
120             statusListenerList.add(listener);
121         }
122         return true;
123     }
124 
125     private boolean checkForPresence(List<StatusListener> statusListenerList, Class<?> aClass) {
126         for (StatusListener e : statusListenerList) {
127             if (e.getClass() == aClass)
128                 return true;
129         }
130         return false;
131     }
132 
133     public void remove(StatusListener listener) {
134         synchronized (statusListenerListLock) {
135             statusListenerList.remove(listener);
136         }
137     }
138 
139     public List<StatusListener> getCopyOfStatusListenerList() {
140         synchronized (statusListenerListLock) {
141             return new ArrayList<StatusListener>(statusListenerList);
142         }
143     }
144 
145 }