001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.log4j.helpers; 019 020import org.apache.log4j.spi.LoggingEvent; 021 022/** 023 024 CyclicBuffer is used by other appenders to hold {@link LoggingEvent 025 LoggingEvents} for immediate or differed display. 026 027 <p>This buffer gives read access to any element in the buffer not 028 just the first or last element. 029 030 @author Ceki Gülcü 031 @since 0.9.0 032 033 */ 034public class CyclicBuffer { 035 036 LoggingEvent[] ea; 037 int first; 038 int last; 039 int numElems; 040 int maxSize; 041 042 /** 043 Instantiate a new CyclicBuffer of at most <code>maxSize</code> events. 044 045 The <code>maxSize</code> argument must a positive integer. 046 047 @param maxSize The maximum number of elements in the buffer. 048 */ 049 public CyclicBuffer(int maxSize) throws IllegalArgumentException { 050 if(maxSize < 1) { 051 throw new IllegalArgumentException("The maxSize argument ("+maxSize+ 052 ") is not a positive integer."); 053 } 054 this.maxSize = maxSize; 055 ea = new LoggingEvent[maxSize]; 056 first = 0; 057 last = 0; 058 numElems = 0; 059 } 060 061 /** 062 Add an <code>event</code> as the last event in the buffer. 063 064 */ 065 public 066 void add(LoggingEvent event) { 067 ea[last] = event; 068 if(++last == maxSize) 069 last = 0; 070 071 if(numElems < maxSize) 072 numElems++; 073 else if(++first == maxSize) 074 first = 0; 075 } 076 077 078 /** 079 Get the <i>i</i>th oldest event currently in the buffer. If 080 <em>i</em> is outside the range 0 to the number of elements 081 currently in the buffer, then <code>null</code> is returned. 082 083 084 */ 085 public 086 LoggingEvent get(int i) { 087 if(i < 0 || i >= numElems) 088 return null; 089 090 return ea[(first + i) % maxSize]; 091 } 092 093 public 094 int getMaxSize() { 095 return maxSize; 096 } 097 098 /** 099 Get the oldest (first) element in the buffer. The oldest element 100 is removed from the buffer. 101 */ 102 public 103 LoggingEvent get() { 104 LoggingEvent r = null; 105 if(numElems > 0) { 106 numElems--; 107 r = ea[first]; 108 ea[first] = null; 109 if(++first == maxSize) 110 first = 0; 111 } 112 return r; 113 } 114 115 /** 116 Get the number of elements in the buffer. This number is 117 guaranteed to be in the range 0 to <code>maxSize</code> 118 (inclusive). 119 */ 120 public 121 int length() { 122 return numElems; 123 } 124 125 /** 126 Resize the cyclic buffer to <code>newSize</code>. 127 128 @throws IllegalArgumentException if <code>newSize</code> is negative. 129 */ 130 public 131 void resize(int newSize) { 132 if(newSize < 0) { 133 throw new IllegalArgumentException("Negative array size ["+newSize+ 134 "] not allowed."); 135 } 136 if(newSize == numElems) 137 return; // nothing to do 138 139 LoggingEvent[] temp = new LoggingEvent[newSize]; 140 141 int loopLen = newSize < numElems ? newSize : numElems; 142 143 for(int i = 0; i < loopLen; i++) { 144 temp[i] = ea[first]; 145 ea[first] = null; 146 if(++first == numElems) 147 first = 0; 148 } 149 ea = temp; 150 first = 0; 151 numElems = loopLen; 152 maxSize = newSize; 153 if (loopLen == newSize) { 154 last = 0; 155 } else { 156 last = loopLen; 157 } 158 } 159}