Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/further/jaudit/http/StatisticsBean.java


1   /*
2    * StatisticsBean.java
3    * Copyright (c) 2001, Kristopher Wehner
4    * Created on September 23, 2001, 7:48 PM
5    */
6   
7   package com.further.jaudit.http;
8   
9   import java.util.Date;
10  import java.util.Iterator;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.Set;
14  import java.util.HashMap;
15  import java.util.HashSet;
16  import java.util.TreeMap;
17  
18  import java.io.IOException;
19  
20  import java.text.NumberFormat;
21  
22  import org.apache.log4j.Category;
23  
24  import com.further.jaudit.SourceDirectory;
25  import com.further.jaudit.SourceFile;
26  import com.further.jaudit.AuditRecord;
27  import com.further.jaudit.SourceMetric;
28  import com.further.jaudit.SystemConfiguration;
29  import com.further.jaudit.ValueGettingVisitor;
30  
31  /**
32   * The statistics bean is responsible for iterating the entire source base
33   * and compiling summary statistics about the source files. These stats include:
34   * <ul>
35   *   <li>Number of files
36   *   <li>Percent of files that have been audited
37   *   <li>Percent of files that are compliant (passing audit)
38   *   <li>Minimum audit age
39   *   <li>Maximum audit age
40   *   <li>For each metric, what percent of files have each value.
41   * </ul>
42   *
43   * @author Kris Wehner <kris@further.com>
44   * @version $Id: StatisticsBean.java,v 1.1.1.1 2001/10/11 16:42:10 krisw Exp $
45   * @since 1.0
46   */
47  public class StatisticsBean {
48      /**
49       * log4j audit debugging channel
50       */
51      private Category category =
52          Category.getInstance(StatisticsBean.class.getName());    
53      /**
54       * The number of files in the system
55       */
56      private int fileCount = 0;
57      /**
58       * The number of files in the system that have been audited at least once
59       */
60      private int auditCount = 0;
61      /**
62       * The number of files in the system that passed their last registered audit
63       */
64      private int compliantCount = 0;
65      /**
66       * The set of audit dates for all the files in the system, for the last
67       * registered audit. 
68       */
69      private Set auditDateSet = new HashSet();
70      /**
71       * The map of metrics. Each key in this map is a string metric abbreviation,
72       * and each value is another HashMap. The keys in the target map are the
73       * metric values and the values in the map are the count of files that have
74       * that value for the metric (as an Integer).
75       */
76      private Map metricMap = new TreeMap();
77      /**
78       * The root source directory being traversed. This is independent of the 
79       * current directory in the DirectoryBean
80       */
81      private SourceDirectory rootDirectory;
82      /**
83       * A map of metric abbreviations to metric full names. This is built 
84       * at construction time from the list of metrics in the system, and queried
85       * to build the statistics display page.
86       */
87      private Map fullNameMap = new HashMap();
88      /**
89       * Get the number of files in the system. This is the compiled count 
90       * of all the individual source files in all the directories.
91       *
92       * @return The number of files in all the directories of the system.
93       */
94      public int getFileCount() {
95          return fileCount;
96      }
97      
98      /**
99       * Get the number of files in the system that have been audited. This
100      * is the files that have ever had an audit registered, rather than 
101      * the files that have a current audit.
102      *
103      * @return The percent of files in the system that have been audited, from 0.0 to 100.0
104      */
105     public String getAuditPercent() {
106         double percentage = 
107             (((double)auditCount / (double)fileCount) * 100.0);
108         NumberFormat numberFormat = NumberFormat.getInstance();
109         numberFormat.setMaximumFractionDigits(2);
110         numberFormat.setMinimumFractionDigits(2);
111         numberFormat.setMinimumIntegerDigits(2);
112         numberFormat.setMaximumIntegerDigits(2);
113         return numberFormat.format(percentage);        
114     }
115     
116     /**
117      * Get the percentage of files in the system whose last audit was compliant.
118      * That is, the number of files that do not need to be modified to 
119      * bring them up to compliance.
120      *
121      * @return The percent of files in the system that have been audited and are 
122      *         compliant from 0.0 to 100.0
123      */
124     public String getCompliantPercent() {
125         double percentage = 
126             (((double)compliantCount / (double)auditCount)) * 100.0;
127         NumberFormat numberFormat = NumberFormat.getInstance();
128         numberFormat.setMaximumFractionDigits(2);
129         numberFormat.setMinimumFractionDigits(2);
130         numberFormat.setMinimumIntegerDigits(2);
131         numberFormat.setMaximumIntegerDigits(2);
132         return numberFormat.format(percentage);
133     }
134     
135     /**
136      * Get the newest audit date from the entire set of audit dates for the 
137      * files in the system.
138      *
139      * @return The newest audit date of any file in the system
140      */
141     public Date getNewestAuditDate() {
142         Date auditDate = null;
143         for (Iterator i = auditDateSet.iterator(); i.hasNext(); ) {
144             Date date = (Date)i.next();
145             if ((auditDate == null) || (auditDate.getTime() < date.getTime()))
146                 auditDate = date;
147         }
148         return auditDate;
149     }
150     
151 
152     /**
153      * Get the oldest audit date from the entire set of audit dates for the 
154      * files in the system.
155      *
156      * @return The oldest audit date of any file in the system
157      */
158     public Date getOldestAuditDate() {
159         Date auditDate = new Date();
160         for (Iterator i = auditDateSet.iterator(); i.hasNext(); ) {
161             Date date = (Date)i.next();
162             if (auditDate.getTime() > date.getTime())
163                 auditDate = date;
164         }
165         return auditDate;
166     }    
167     
168     /**
169      * Get an iterator over the defined metrics in the system. The values
170      * returned by the iterator are string keys that can be used to access
171      * the values for that metric and what percentage of source files have
172      * that metric value
173      *
174      * @return An iterator over the metric identifiers
175      */
176     public Iterator getMetricIterator() {
177         return metricMap.keySet().iterator();
178     }
179     
180     /**
181      * Get an iterator over the values of a particular metric. This iterator
182      * returns string values that can be used (along with the metric id) to
183      * retreive the percentage of files that have that given metric value
184      *
185      * @param id The id of the metric to obtain an iterator over
186      * @return An iterator over the values of the metric
187      */
188     public Iterator getValuesIterator(String id) {
189         Map valuesMap = (Map)metricMap.get(id);
190         return valuesMap.keySet().iterator();
191     }
192     
193     /**
194      * Get the percentage of files that have the given metric value, for the
195      * specified metric id and metric value. This returns a floating point
196      * percentage between 0.0 and 100.0
197      *
198      * @param id The id of the metric to obtain statistics for
199      * @param value The metric value to retreive the percentage for
200      * @return The floating point percentage of files that have the given
201      *         metric value
202      */
203     public String getFilePercentage(String id, String value) {
204         Map valuesMap = (Map)metricMap.get(id);
205         int valueCount = ((Integer)valuesMap.get(value)).intValue();
206         double percentage = 
207             (((double)valueCount / (double)fileCount) * 100.0);
208         NumberFormat numberFormat = NumberFormat.getInstance();
209         numberFormat.setMaximumFractionDigits(2);
210         numberFormat.setMinimumFractionDigits(2);
211         numberFormat.setMinimumIntegerDigits(2);
212         numberFormat.setMaximumIntegerDigits(2);
213         return numberFormat.format(percentage);        
214     }
215     
216     /**
217      * The recursive call to traverse the source files in a given directory.
218      * This first calls itself on all subdirectories in the directory, then
219      * iterates over all the files in the directory compiling the statistics
220      * for those files.
221      *
222      * @param sourceDirectory The source directory to traverse
223      */
224     private void traverseDirectory(SourceDirectory sourceDirectory) 
225         throws IOException {
226         for (Iterator i = sourceDirectory.getDirectoryIterator(); i.hasNext(); ) {
227             String directoryName = (String)i.next();
228             SourceDirectory directory = 
229                 sourceDirectory.getSourceDirectory(directoryName);
230             traverseDirectory(directory);
231         }
232         for (Iterator i = sourceDirectory.getFileIterator(); i.hasNext(); ) {
233             String fileName = (String)i.next();
234             SourceFile sourceFile = 
235                 sourceDirectory.getSourceFile(fileName);
236             buildStatistics(sourceFile);            
237         }        
238     }
239     
240     /**
241      * Build the statistics for an individual source file. This method was
242      * refactored out for readabilitys sake from traverseDirectory, and is
243      * only called from there.
244      *
245      * @param sourceFile The source file to build the statistics for
246      */
247     private void buildStatistics(SourceFile sourceFile) {
248         // Compile the statistics
249         fileCount++;
250         if (sourceFile.passedLastAudit())
251             compliantCount++;
252         if (sourceFile.hasBeenAudited())
253             auditCount++;
254         
255         if (!sourceFile.hasBeenAudited())
256             return;
257         
258         // The only audit that is relevant is the latest one. The last
259         // audit record is extracted, then the internal metrics are individually
260         // examined to update the metric tables.
261         AuditRecord auditRecord = 
262             getNewestAuditRecord(sourceFile.getAuditRecords());
263         category.debug("Last audit record for " + sourceFile.getFileName() + " is " + auditRecord.getAuditDate());
264         for (Iterator j = auditRecord.getMetrics().iterator(); j.hasNext(); ) {
265             SourceMetric metric = (SourceMetric)j.next();
266             ValueGettingVisitor visitor = new ValueGettingVisitor();
267             metric.accept(visitor);
268             String metricValue = visitor.getStringValue();
269             incrementMetricCount(metric.getMetricAbbreviation(), metricValue);
270         }
271     }
272     
273     /**
274      * Retreive the newest audit record from the given list of audit
275      * records. This does a simple O(n) pass over the list of audit records,
276      * assuming they are stored unorderd.
277      *
278      * @param auditRecords The list of audit records, in no particular order
279      * @return The newest audit record in the list, or null if the list is
280      *         empty
281      */
282     private AuditRecord getNewestAuditRecord(List auditRecords) {
283         if (auditRecords.size() > 0) {
284             AuditRecord auditRecord = (AuditRecord)auditRecords.get(0);                
285             for (Iterator j = auditRecords.iterator(); j.hasNext(); ) {
286                 AuditRecord record = (AuditRecord)j.next();
287                 if (record.getAuditDate().after(auditRecord.getAuditDate()))
288                     auditRecord = record;
289             }      
290             return auditRecord;
291         }
292         return null;
293     }
294     
295     /**
296      * Increment the count of a given metric value and metric id. This method
297      * updates the metricMap to increment the integer value at the value entry
298      * if it exists, and sets it to 1 if it does not.
299      *
300      * @param id The metric id for the metric to update
301      * @param value The metric value (as a string) to increment the count for
302      */
303     private void incrementMetricCount(String id, String value) {
304         if (!metricMap.containsKey(id))
305             metricMap.put(id,new TreeMap());
306         Map valueMap = (Map)metricMap.get(id);
307         if (!valueMap.containsKey(value))
308             valueMap.put(value, new Integer(0));
309         int valueCount = ((Integer)valueMap.get(value)).intValue();
310         valueCount++;
311         category.debug("Metric value for " + id + " is " + value + ", count is " + valueCount);
312         valueMap.put(value, new Integer(valueCount));        
313     }
314     
315     /**
316      * Get the full name of the given metric from the metric abbreviation.
317      * This is used for displaying the statistics summary in stats.jsp
318      *
319      * @param id The metric id for the given metric
320      * @return The full name of the metric
321      */
322     public String getFullName(String id) {
323         return (String)fullNameMap.get(id);
324     }
325     
326     /**
327      * The compile statistics method causes the statistics bean to traverse the
328      * the entire source tree and build the statistics for the sourcebase. This
329      * is the one driver method that must be called before querying the statistics
330      * for display
331      */
332     public void compileStatistics()
333         throws IOException {
334         rootDirectory = 
335             new SourceDirectory(SystemConfiguration.getRootSourceDirectory());
336         traverseDirectory(rootDirectory);
337     }
338     
339     /** 
340      * Create a new StatisticsBean. This is the required empty constructor 
341      * to use the bean from a jsp. Use compileStatistics()
342      * in order to prepare the statistics.
343      */
344     public StatisticsBean() {
345         List metrics = 
346             SystemConfiguration.createMetrics();
347         for (Iterator i = metrics.iterator(); i.hasNext(); ) {
348             SourceMetric metric = (SourceMetric)i.next();
349             fullNameMap.put(metric.getMetricAbbreviation(), metric.getMetricName());
350         }        
351     }
352 
353 }