package com.limegroup.gnutella.statistics; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Field; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; import com.limegroup.gnutella.ErrorService; import com.limegroup.gnutella.util.IntBuffer; /** * This class provides a default implementation of the <tt>Statistic</tt> * interface, providing such functionality as keeping track of the * history for the given statistic, providing access to the average * value, the maximum value, etc. */ public abstract class AbstractStatistic implements Statistic { /** * Constant for the <tt>StatisticsManager</tt> for use in subclasses. */ protected static final StatisticsManager STATS_MANAGER = StatisticsManager.instance(); /** * <tt>IntBuffer</tt> for recording stats data -- initialized to * an empty buffer until stats are actually recorded. */ protected final IntBuffer _buffer = new IntBuffer(HISTORY_LENGTH); /** * Int for the statistic currently being added to. */ protected volatile int _current = 0; /** * Int for the most recently stored statistic. */ private volatile int _lastStored = 0; /** * Variable for the total number of messages received for this * statistic. */ protected volatile double _total = 0; /** * The total number of stats recorded. */ protected volatile int _totalStatsRecorded = 0; /** * The maximum value ever recorded for any time period. */ protected volatile double _max = 0; private Writer _writer; private boolean _writeStat = false; private int _numWriters = 0; /** * The file name to write stat data to. If this is null or the empty * string, we attempt to derive the appropriate file name via * reflection. */ protected String _fileName; /** * Constructs a new <tt>Statistic</tt> instance. */ protected AbstractStatistic() {} // inherit doc comment public double getTotal() { return _total; } // inherit doc comment public double getAverage() { if(_totalStatsRecorded == 0) return 0; return _total/_totalStatsRecorded; } // inherit doc comment public double getMax() { return _max; } public int getCurrent() { return _current; } public int getLastStored() { return _lastStored; } // inherit doc comment public void incrementStat() { _current++; _total++; } // inherit doc comment public void addData(int data) { _current += data; _total += data; } // inherit doc comment public IntBuffer getStatHistory() { synchronized(_buffer) { initializeBuffer(); return _buffer; } } // inherit doc comment public void clearData() { _current = 0; _total = 0; _totalStatsRecorded = 0; _max = 0; synchronized(_buffer) { _buffer.clear(); } } // inherit doc comment public void storeCurrentStat() { synchronized(_buffer) { initializeBuffer(); _buffer.addLast(_current); } if(_current > _max) { _max = _current; } if(_writeStat) { if(_writer != null) { try { _writer.write(Integer.toString(_current)); _writer.write(","); _writer.flush(); } catch(IOException e) { ErrorService.error(e); } } } _lastStored = _current; _current = 0; _totalStatsRecorded++; } // inherit doc comment public synchronized void setWriteStatToFile(boolean write) { if(write) { _numWriters++; _writeStat = true; if(_numWriters == 1) { try { if(_fileName == null || _fileName.equals("")) { Class superclass = getClass().getSuperclass(); Class declaringClass = getClass().getDeclaringClass(); List fieldsList = new LinkedList(); if(superclass != null) { fieldsList.addAll(Arrays.asList(superclass.getFields())); } if(declaringClass != null) { fieldsList.addAll(Arrays.asList(declaringClass.getFields())); } fieldsList.addAll(Arrays.asList(getClass().getFields())); Field[] fields = (Field[])fieldsList.toArray(new Field[0]); for(int i=0; i<fields.length; i++) { try { Object fieldObject = fields[i].get(null); if(fieldObject.equals(this)) { StringTokenizer st = new StringTokenizer(fields[i].toString()); while(st.hasMoreTokens()) { _fileName = st.nextToken(); } _fileName = _fileName.substring(34); } } catch(IllegalAccessException e) { continue; } } } _writer = new FileWriter(_fileName, false); } catch(IOException e) { ErrorService.error(e); } } } else if(_numWriters != 0) { _numWriters--; } if(_numWriters == 0) { _writeStat = false; _writer = null; } } /** * Constructs the <tt>IntBuffer</tt> with 0 for all values if it is * not already constructed. */ protected final void initializeBuffer() { if(_buffer.isEmpty()) { for(int i=0; i<HISTORY_LENGTH; i++) { _buffer.addLast(0); } } } }