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; 015 016import java.util.ArrayList; 017import java.util.List; 018 019import ch.qos.logback.core.helpers.CyclicBuffer; 020import ch.qos.logback.core.spi.LogbackLock; 021import ch.qos.logback.core.status.OnConsoleStatusListener; 022import ch.qos.logback.core.status.Status; 023import ch.qos.logback.core.status.StatusListener; 024import ch.qos.logback.core.status.StatusManager; 025 026public class BasicStatusManager implements StatusManager { 027 028 public static final int MAX_HEADER_COUNT = 150; 029 public static final int TAIL_SIZE = 150; 030 031 int count = 0; 032 033 // protected access was requested in http://jira.qos.ch/browse/LBCORE-36 034 final protected List<Status> statusList = new ArrayList<Status>(); 035 final protected CyclicBuffer<Status> tailBuffer = new CyclicBuffer<Status>(TAIL_SIZE); 036 final protected LogbackLock statusListLock = new LogbackLock(); 037 038 int level = Status.INFO; 039 040 // protected access was requested in http://jira.qos.ch/browse/LBCORE-36 041 final protected List<StatusListener> statusListenerList = new ArrayList<StatusListener>(); 042 final protected LogbackLock statusListenerListLock = new LogbackLock(); 043 044 // Note on synchronization 045 // This class contains two separate locks statusListLock and 046 // statusListenerListLock guarding respectively the statusList+tailBuffer and 047 // statusListenerList fields. The locks are used internally 048 // without cycles. They are exposed to derived classes which should be careful 049 // not to create deadlock cycles. 050 051 /** 052 * Add a new status object. 053 * 054 * @param newStatus the status message to add 055 */ 056 public void add(Status newStatus) { 057 // LBCORE-72: fire event before the count check 058 fireStatusAddEvent(newStatus); 059 060 count++; 061 if (newStatus.getLevel() > level) { 062 level = newStatus.getLevel(); 063 } 064 065 synchronized (statusListLock) { 066 if (statusList.size() < MAX_HEADER_COUNT) { 067 statusList.add(newStatus); 068 } else { 069 tailBuffer.add(newStatus); 070 } 071 } 072 073 } 074 075 public List<Status> getCopyOfStatusList() { 076 synchronized (statusListLock) { 077 List<Status> tList = new ArrayList<Status>(statusList); 078 tList.addAll(tailBuffer.asList()); 079 return tList; 080 } 081 } 082 083 private void fireStatusAddEvent(Status status) { 084 synchronized (statusListenerListLock) { 085 for (StatusListener sl : statusListenerList) { 086 sl.addStatusEvent(status); 087 } 088 } 089 } 090 091 public void clear() { 092 synchronized (statusListLock) { 093 count = 0; 094 statusList.clear(); 095 tailBuffer.clear(); 096 } 097 } 098 099 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}