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
55       *                the status message to add
56       */
57      public void add(Status newStatus) {
58          // LBCORE-72: fire event before the count check
59          fireStatusAddEvent(newStatus);
60  
61          count++;
62          if (newStatus.getLevel() > level) {
63              level = newStatus.getLevel();
64          }
65  
66          synchronized (statusListLock) {
67              if (statusList.size() < MAX_HEADER_COUNT) {
68                  statusList.add(newStatus);
69              } else {
70                  tailBuffer.add(newStatus);
71              }
72          }
73  
74      }
75  
76      public List<Status> getCopyOfStatusList() {
77          synchronized (statusListLock) {
78              List<Status> tList = new ArrayList<Status>(statusList);
79              tList.addAll(tailBuffer.asList());
80              return tList;
81          }
82      }
83  
84      private void fireStatusAddEvent(Status status) {
85          synchronized (statusListenerListLock) {
86              for (StatusListener sl : statusListenerList) {
87                  sl.addStatusEvent(status);
88              }
89          }
90      }
91  
92      public void clear() {
93          synchronized (statusListLock) {
94              count = 0;
95              statusList.clear();
96              tailBuffer.clear();
97          }
98      }
99  
100     public int getLevel() {
101         return level;
102     }
103 
104     public int getCount() {
105         return count;
106     }
107 
108     /**
109      * This implementation does not allow duplicate installations of OnConsoleStatusListener
110      * @param listener
111      */
112     public boolean add(StatusListener listener) {
113         synchronized (statusListenerListLock) {
114             if (listener instanceof OnConsoleStatusListener) {
115                 boolean alreadyPresent = checkForPresence(statusListenerList, listener.getClass());
116                 if (alreadyPresent)
117                     return false;
118             }
119             statusListenerList.add(listener);
120         }
121         return true;
122     }
123 
124     private boolean checkForPresence(List<StatusListener> statusListenerList, Class<?> aClass) {
125         for (StatusListener e : statusListenerList) {
126             if (e.getClass() == aClass)
127                 return true;
128         }
129         return false;
130     }
131 
132     public void remove(StatusListener listener) {
133         synchronized (statusListenerListLock) {
134             statusListenerList.remove(listener);
135         }
136     }
137 
138     public List<StatusListener> getCopyOfStatusListenerList() {
139         synchronized (statusListenerListLock) {
140             return new ArrayList<StatusListener>(statusListenerList);
141         }
142     }
143 
144 }