001 /*
002 Licensed to the Apache Software Foundation (ASF) under one
003 or more contributor license agreements. See the NOTICE file
004 distributed with this work for additional information
005 regarding copyright ownership. The ASF licenses this file
006 to you under the Apache License, Version 2.0 (the
007 "License"); you may not use this file except in compliance
008 with the License. You may obtain a copy of the License at
009
010 http://www.apache.org/licenses/LICENSE-2.0
011
012 Unless required by applicable law or agreed to in writing,
013 software distributed under the License is distributed on an
014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 KIND, either express or implied. See the License for the
016 specific language governing permissions and limitations
017 under the License.
018 */
019 package org.apache.wiki.util;
020
021 import java.util.AbstractList;
022 import java.util.ArrayList;
023 import java.util.Iterator;
024 import java.util.concurrent.locks.ReadWriteLock;
025 import java.util.concurrent.locks.ReentrantReadWriteLock;
026
027 /**
028 * Provides a List in which all items store their addition time. This
029 * can then be used to clean the list from old items.
030 * <p>
031 * This class is thread-safe - all modifications are blocking, but
032 * reading is non-blocking (unless a write is ongoing).
033 *
034 * @param <T> The class you wish to store here
035 * @since 2.8
036 */
037 public class TimedCounterList<T> extends AbstractList<T>
038 {
039 private ArrayList<CounterItem<T>> m_list = new ArrayList<CounterItem<T>>();
040 private ReadWriteLock m_lock = new ReentrantReadWriteLock();
041
042 /**
043 * {@inheritDoc}
044 */
045 @Override
046 public T set( int index, T element )
047 {
048 m_lock.writeLock().lock();
049
050 T t;
051
052 try
053 {
054 t = m_list.set(index,new CounterItem<T>(element)).m_obj;
055 }
056 finally
057 {
058 m_lock.writeLock().unlock();
059 }
060
061 return t;
062 }
063
064 /**
065 * {@inheritDoc}
066 */
067 @Override
068 public T get( int index )
069 {
070 m_lock.readLock().lock();
071
072 T t;
073
074 try
075 {
076 t = m_list.get(index).m_obj;
077 }
078 finally
079 {
080 m_lock.readLock().unlock();
081 }
082
083 return t;
084 }
085
086 /**
087 * {@inheritDoc}
088 */
089 @Override
090 public int size()
091 {
092 m_lock.readLock().lock();
093 int size = 0;
094
095 try
096 {
097 size = m_list.size();
098 }
099 finally
100 {
101 m_lock.readLock().unlock();
102 }
103
104 return size;
105 }
106
107 /**
108 * {@inheritDoc}
109 */
110 @Override
111 public void add( int index, T element )
112 {
113 m_lock.writeLock().lock();
114
115 try
116 {
117 m_list.add(index, new CounterItem<T>(element));
118 }
119 finally
120 {
121 m_lock.writeLock().unlock();
122 }
123 }
124
125 /**
126 * {@inheritDoc}
127 */
128 @Override
129 public T remove( int index )
130 {
131 m_lock.writeLock().lock();
132 T t;
133
134 try
135 {
136 t = m_list.remove( index ).m_obj;
137 }
138 finally
139 {
140 m_lock.writeLock().unlock();
141 }
142
143 return t;
144 }
145
146 /**
147 * Returns the count how many times this object is available in
148 * this list, using equals().
149 *
150 * @param obj The object to count.
151 * @return The count of the objects.
152 */
153 public int count( T obj )
154 {
155 int c = 0;
156 m_lock.readLock().lock();
157
158 try
159 {
160 for( CounterItem i : m_list )
161 {
162 if( i.m_obj.equals( obj ) )
163 {
164 c++;
165 }
166 }
167 }
168 finally
169 {
170 m_lock.readLock().unlock();
171 }
172
173 return c;
174 }
175
176 /**
177 * Performs a cleanup of all items older than maxage.
178 *
179 * @param maxage The maximum age in milliseconds after an item is removed.
180 */
181 public void cleanup( long maxage )
182 {
183 m_lock.writeLock().lock();
184
185 try
186 {
187 long now = System.currentTimeMillis();
188
189 for( Iterator<CounterItem<T>> i = m_list.iterator(); i.hasNext(); )
190 {
191 CounterItem<T> ci = i.next();
192
193 long age = now - ci.m_addTime;
194
195 if( age > maxage )
196 {
197 i.remove();
198 }
199 }
200 }
201 finally
202 {
203 m_lock.writeLock().unlock();
204 }
205 }
206
207 /**
208 * Returns the time when this particular item was added on the list.
209 *
210 * @param index The index of the object.
211 * @return The addition time in milliseconds (@see System.currentTimeMillis()).
212 */
213 public long getAddTime( int index )
214 {
215 m_lock.readLock().lock();
216 long res = 0;
217
218 try
219 {
220 res = m_list.get( index ).m_addTime;
221 }
222 finally
223 {
224 m_lock.readLock().unlock();
225 }
226
227 return res;
228 }
229
230 private static class CounterItem<E>
231 {
232 private E m_obj;
233 private long m_addTime;
234
235 public CounterItem(E o)
236 {
237 m_addTime = System.currentTimeMillis();
238 m_obj = o;
239 }
240 }
241
242
243 }