KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > junit > viewer > server > ReportDatabase


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.junit.viewer.server;
17
18 import com.google.gwt.junit.client.Benchmark;
19 import com.google.gwt.junit.viewer.client.Report;
20 import com.google.gwt.junit.viewer.client.ReportSummary;
21
22 import org.w3c.dom.Document JavaDoc;
23
24 import java.io.File JavaDoc;
25 import java.io.FilenameFilter JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import javax.xml.parsers.DocumentBuilder JavaDoc;
33 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
34
35 /**
36  * Serves up benchmark reports created during JUnit execution.
37  *
38  * The benchmark reports are read from the path specified by the system property
39  * named <code>Benchmark.REPORT_PATH</code>. In the case the property is not
40  * set, they are read from the user's current working directory.
41  */

42 public class ReportDatabase {
43
44   /**
45    * Indicates that a supplied path was invalid.
46    *
47    */

48   public static class BadPathException extends RuntimeException JavaDoc {
49     String JavaDoc path;
50
51     public BadPathException(String JavaDoc path) {
52       super("The path " + path + " does not exist.");
53       this.path = path;
54     }
55
56     public String JavaDoc getPath() {
57       return path;
58     }
59   }
60
61   private static class ReportEntry {
62     private ReportSummary summary;
63     private Report report;
64     private long lastModified;
65
66     public ReportEntry(Report report, ReportSummary summary, long lastModified) {
67       this.report = report;
68       this.summary = summary;
69       this.lastModified = lastModified;
70     }
71   }
72
73   private static class ReportFile {
74     File JavaDoc file;
75     long lastModified;
76
77     ReportFile(File JavaDoc f) {
78       this.file = f;
79       this.lastModified = f.lastModified();
80     }
81   }
82
83   /**
84    * The amount of time to go between report updates.
85    */

86   private static final int UPDATE_DURATION_MILLIS = 30000;
87
88   private static ReportDatabase database = new ReportDatabase();
89
90   public static ReportDatabase getInstance() {
91     return database;
92   }
93
94   private static String JavaDoc getReportId(File JavaDoc f) {
95     return f.getName();
96   }
97
98   /**
99    * A list of all reports by id.
100    */

101   private Map JavaDoc/* <String,ReportEntry> */reports = new HashMap JavaDoc/* <String,ReportEntry> */();
102
103   /**
104    * The last time we updated our reports.
105    */

106   private long lastUpdateMillis = -1L;
107
108   /**
109    * Lock for updating from file system. (Guarantees a single update while not
110    * holding reportsLock open).
111    */

112   private Object JavaDoc updateLock = new Object JavaDoc();
113
114   /**
115    * Are we currently undergoing updating?
116    */

117   private boolean updating = false;
118
119   /**
120    * Lock for reports.
121    */

122   private Object JavaDoc reportsLock = new Object JavaDoc();
123
124   /**
125    * The path to read benchmark reports from.
126    */

127   private final String JavaDoc reportPath;
128
129   private ReportDatabase() throws BadPathException {
130     String JavaDoc path = System.getProperty(Benchmark.REPORT_PATH);
131     if (path == null || path.trim().equals("")) {
132       path = System.getProperty("user.dir");
133     }
134     reportPath = path;
135
136     if (!new File JavaDoc(reportPath).exists()) {
137       throw new BadPathException(reportPath);
138     }
139   }
140
141   public Report getReport(String JavaDoc reportId) {
142     synchronized (reportsLock) {
143       ReportEntry entry = (ReportEntry) reports.get(reportId);
144       return entry == null ? null : entry.report;
145     }
146   }
147
148   public List JavaDoc/* <ReportSummary> */getReportSummaries() {
149
150     /**
151      * There are probably ways to make this faster, but I've taken basic
152      * precautions to try to make this scale ok with multiple clients.
153      */

154
155     boolean update = false;
156
157     // See if we need to do an update
158
// Go ahead and let others continue reading, even if an update is required.
159
synchronized (updateLock) {
160       if (!updating) {
161         long currentTime = System.currentTimeMillis();
162
163         if (currentTime > lastUpdateMillis + UPDATE_DURATION_MILLIS) {
164           update = updating = true;
165         }
166       }
167     }
168
169     if (update) {
170       updateReports();
171     }
172
173     synchronized (reportsLock) {
174       List JavaDoc/* <ReportSummary> */summaries = new ArrayList JavaDoc/* <ReportSummary> */(
175           reports.size());
176       for (Iterator JavaDoc it = reports.values().iterator(); it.hasNext();) {
177         ReportEntry entry = (ReportEntry) it.next();
178         summaries.add(entry.summary);
179       }
180       return summaries;
181     }
182   }
183
184   private void updateReports() {
185
186     File JavaDoc path = new File JavaDoc(reportPath);
187
188     File JavaDoc[] files = path.listFiles(new FilenameFilter JavaDoc() {
189       public boolean accept(File JavaDoc f, String JavaDoc name) {
190         return name.startsWith("report-") && name.endsWith(".xml");
191       }
192     });
193
194     Map JavaDoc filesToUpdate = new HashMap JavaDoc();
195     Map JavaDoc filesById = new HashMap JavaDoc();
196     for (int i = 0; i < files.length; ++i) {
197       File JavaDoc f = files[i];
198       filesById.put(getReportId(f), new ReportFile(f));
199     }
200
201     // Lock temporarily so we can determine what needs updating
202
// (This could be a read-lock - not a general read-write lock,
203
// if we moved dead report removal outside of this critical section).
204
synchronized (reportsLock) {
205
206       // Add reports which need to be updated or are new
207
for (int i = 0; i < files.length; ++i) {
208         File JavaDoc file = files[i];
209         String JavaDoc reportId = getReportId(file);
210         ReportEntry entry = (ReportEntry) reports.get(reportId);
211         if (entry == null || entry.lastModified < file.lastModified()) {
212           filesToUpdate.put(reportId, null);
213         }
214       }
215
216       // Remove reports which no longer exist
217
for (Iterator JavaDoc it = reports.keySet().iterator(); it.hasNext();) {
218         String JavaDoc id = (String JavaDoc) it.next();
219         if (filesById.get(id) == null) {
220           it.remove();
221         }
222       }
223     }
224
225     try {
226       DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
227       factory.setIgnoringElementContentWhitespace(true);
228       factory.setIgnoringComments(true);
229       DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
230
231       for (Iterator JavaDoc it = filesToUpdate.keySet().iterator(); it.hasNext();) {
232         String JavaDoc id = (String JavaDoc) it.next();
233         ReportFile reportFile = (ReportFile) filesById.get(id);
234         String JavaDoc filePath = reportFile.file.getAbsolutePath();
235         Document JavaDoc doc = builder.parse(filePath);
236         Report report = ReportXml.fromXml(doc.getDocumentElement());
237         report.setId(id);
238         ReportSummary summary = report.getSummary();
239         long lastModified = new File JavaDoc(filePath).lastModified();
240         filesToUpdate.put(id, new ReportEntry(report, summary, lastModified));
241       }
242
243       // Update the reports
244
synchronized (reportsLock) {
245         for (Iterator JavaDoc it = filesToUpdate.keySet().iterator(); it.hasNext();) {
246           String JavaDoc id = (String JavaDoc) it.next();
247           reports.put(id, filesToUpdate.get(id));
248         }
249       }
250     } catch (Exception JavaDoc e) {
251       // Even if we got an error, we'll just try again on the next update
252
// This might happen if a report has only been partially written, for
253
// example.
254
e.printStackTrace();
255     }
256
257     synchronized (updateLock) {
258       updating = false;
259       lastUpdateMillis = System.currentTimeMillis();
260     }
261   }
262 }
263
Popular Tags