001: /*
002: * Hammurapi
003: * Automated Java code review system.
004: * Copyright (C) 2004 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.org
021: * e-Mail: support@hammurapi.biz
022: */
023: package org.hammurapi;
024:
025: import java.io.IOException;
026: import java.io.InputStreamReader;
027: import java.sql.SQLException;
028: import java.sql.Timestamp;
029: import java.text.MessageFormat;
030: import java.util.Collection;
031: import java.util.Date;
032: import java.util.Iterator;
033: import java.util.Map;
034:
035: import javax.sql.DataSource;
036:
037: import org.apache.tools.ant.BuildException;
038: import org.apache.tools.ant.Project;
039: import org.hammurapi.results.InspectorSummary;
040: import org.hammurapi.results.ResultsFactory;
041: import org.hammurapi.results.ReviewResults;
042: import org.hammurapi.results.quick.Inspector;
043: import org.hammurapi.results.quick.ResultsEngine;
044:
045: import com.pavelvlasov.jsel.CompilationUnit;
046: import com.pavelvlasov.metrics.Metric;
047: import com.pavelvlasov.review.Signed;
048: import com.pavelvlasov.review.SourceMarker;
049: import com.pavelvlasov.sql.SQLProcessor;
050: import com.pavelvlasov.sql.Transaction;
051: import com.pavelvlasov.sql.hypersonic.HypersonicDataSource;
052: import com.pavelvlasov.sql.hypersonic.HypersonicStandaloneDataSource;
053: import com.pavelvlasov.sql.hypersonic.HypersonicTmpDataSource;
054: import com.pavelvlasov.util.DispatcherAware;
055: import com.pavelvlasov.util.DispatchingVisitor;
056: import com.pavelvlasov.util.OrderedTarget;
057: import com.pavelvlasov.util.DispatchingVisitor.Stats;
058:
059: public class QuickResultsCollector implements DispatcherAware,
060: OrderedTarget {
061: static final byte RESULT_NEW = 0;
062: static final byte RESULT_PREV = 1;
063: static final byte RESULT_UNTOUCHED = 2;
064:
065: private final QuickHammurapiTask task;
066: private Collection listeners;
067: private long start = System.currentTimeMillis();
068: private DispatchingVisitor dispatcher;
069:
070: DataSource getDataSource() {
071: return dataSource;
072: }
073:
074: ResultsEngine getEngine() {
075: return engine;
076: }
077:
078: SQLProcessor getProcessor() {
079: return processor;
080: }
081:
082: private HypersonicDataSource dataSource;
083: private SQLProcessor processor;
084: private ResultsEngine engine;
085:
086: QuickResultsCollector(QuickHammurapiTask task, String title,
087: Collection listeners) throws ClassNotFoundException,
088: IOException, SQLException {
089: this .task = task;
090: this .listeners = listeners;
091:
092: final String initScript = "org/hammurapi/results/simple/Quickurapi.Hypersonic.sql";
093: if (task.database == null) {
094: dataSource = new HypersonicTmpDataSource(initScript);
095: } else {
096: dataSource = new HypersonicStandaloneDataSource(
097: task.database.getAbsolutePath(), new Transaction() {
098:
099: public boolean execute(SQLProcessor processor)
100: throws SQLException {
101: try {
102: processor
103: .executeScript(new InputStreamReader(
104: getClass()
105: .getClassLoader()
106: .getResourceAsStream(
107: initScript)));
108: } catch (IOException e) {
109: throw new BuildException(
110: "Cannot initialize database", e);
111: }
112: return true;
113: }
114: });
115: }
116: processor = new SQLProcessor(dataSource, null);
117: engine = new ResultsEngine(processor);
118: }
119:
120: public void shutdown() throws SQLException {
121: dataSource.shutdown();
122: }
123:
124: // Second to visit, second from the end to leave
125: private Integer order = new Integer(Integer.MIN_VALUE + 1);
126:
127: public Integer getOrder() {
128: return order;
129: }
130:
131: public boolean visit(CompilationUnit compilationUnit) {
132: log(compilationUnit.getRelativeName() + " - reviewing");
133: ResultsFactory.pushThreadResults(ResultsFactory.getInstance()
134: .newReviewResults(compilationUnit));
135:
136: if (dispatcher != null) {
137: dispatcher.getThreadStats().reset();
138: }
139: return true;
140: }
141:
142: private int counter = 0;
143:
144: private static MessageFormat messageFormat = new MessageFormat(
145: "{0,date, yyyy/MM/dd HH:mm:ss} Progress: {1} file(s). Elapsed time: {2} min. {3} sec. ");
146:
147: public void leave(CompilationUnit compilationUnit)
148: throws HammurapiException, SQLException {
149: Iterator it = listeners.iterator();
150: ReviewResults results = (ReviewResults) ResultsFactory
151: .popThreadResults();
152: results.commit();
153: while (it.hasNext()) {
154: if (dispatcher != null) {
155: Stats threadStats = dispatcher.getThreadStats();
156: results.setCodeBase(threadStats.getVisits());
157: results.setReviewsNumber(threadStats.getInvocations());
158: }
159: ((Listener) it.next()).onReview(results);
160: }
161:
162: // Result
163: /*
164: * int Id,
165: * long Codebase,
166: * java.sql.Timestamp ResultDate,
167: * Short MaxSeverity,
168: * long Reviews,
169: * double ViolationLevel,
170: * long Violations,
171: * long WaivedViolations,
172: * String Name,
173: * boolean HasWarnings,
174: * String PackageName,
175: * byte State,
176: * long CuSize,
177: * long CuChecksum
178: */
179: int resultId = processor.nextPK("PRIMARY_KEY", "RESULT");
180: String packageName = compilationUnit.getPackage().getName();
181: engine.insertResult(resultId, results.getCodeBase(),
182: new Timestamp(results.getDate().getTime()), results
183: .getMaxSeverity() == null ? null : new Short(
184: results.getMaxSeverity().shortValue()), results
185: .getReviewsNumber(), results
186: .getViolationLevel(), results
187: .getViolationsNumber(), results
188: .getWaivedViolationsNumber(),
189: results.getName(), results.hasWarnings(), packageName,
190: RESULT_NEW, compilationUnit.getSize(), compilationUnit
191: .getCheckSum());
192:
193: // Metric
194: Iterator mit = results.getMetrics().values().iterator();
195: while (mit.hasNext()) {
196: Metric metric = (Metric) mit.next();
197: /*
198: * int ResultId,
199: * String Name,
200: * double MinValue,
201: * double MaxValue,
202: * double MetricTotal,
203: * int Measurements
204: */
205: engine.insertMetric(resultId, metric.getName(), metric
206: .getMin(), metric.getMax(), metric.getTotal(),
207: metric.getNumber());
208: }
209:
210: // Inspector
211: Iterator sit = results.getSeveritySummary().values().iterator();
212: while (sit.hasNext()) {
213: Iterator iit = ((Map) sit.next()).values().iterator();
214: while (iit.hasNext()) {
215: InspectorSummary is = (InspectorSummary) iit.next();
216: Inspector dis = engine.getInspector(packageName, is
217: .getName(), resultId);
218: if (dis == null) {
219: /*
220: * String PackageName,
221: * String Name,
222: * short Severity,
223: * String Description,
224: * String ConfigInfo,
225: * int Violations,
226: * int WaivedViolations
227: */
228: engine.insertInspector(packageName, is.getName(),
229: resultId, is.getSeverity() == null ? 0 : is
230: .getSeverity().shortValue(), is
231: .getDescription(), is
232: .getConfigInfo(), is
233: .getLocationsCount(), 0);
234: } else {
235: engine.addInspectorViolations(is
236: .getLocationsCount(), packageName, is
237: .getName());
238: }
239: }
240: }
241:
242: // Warning
243: Iterator wit = results.getWarnings().iterator();
244: while (wit.hasNext()) {
245: Violation warning = (Violation) wit.next();
246: InspectorDescriptor descriptor = warning.getDescriptor();
247: if (descriptor != null) {
248: Inspector dis = engine.getInspector(packageName,
249: descriptor.getName(), resultId);
250: if (dis == null) {
251: /*
252: * String PackageName,
253: * String Name,
254: * short Severity,
255: * String Description,
256: * String ConfigInfo,
257: * int Violations,
258: * int WaivedViolations
259: */
260: engine.insertInspector(packageName, descriptor
261: .getName(), resultId, descriptor
262: .getSeverity() == null ? 0 : descriptor
263: .getSeverity().shortValue(), descriptor
264: .getDescription(), null, 0, 0);
265: }
266: }
267:
268: int warningId = processor.nextPK("PRIMARY_KEY", "WARNING");
269: /*
270: * int Id,
271: * int ResultId,
272: * String PackageName,
273: * String Inspector,
274: * String Message,
275: * String Source,
276: * Integer Line,
277: * Integer Col,
278: * String SourceSignature
279: */
280: SourceMarker source = warning.getSource();
281: engine.insertWarning(warningId, resultId, packageName,
282: descriptor.getName(), warning.getMessage(),
283: source == null ? null : source.getSourceURL(),
284: source == null ? null : new Integer(source
285: .getLine()), source == null ? null
286: : new Integer(source.getColumn()),
287: source instanceof Signed ? ((Signed) source)
288: .getSignature() : null);
289: }
290:
291: ++counter;
292: long now = System.currentTimeMillis();
293:
294: long elapsedSec = (now - start) / 1000;
295: long min = elapsedSec / 60;
296: long sec = elapsedSec % 60;
297:
298: task.log(messageFormat.format(
299: new Object[] { new Date(now), new Integer(counter),
300: new Long(min), new Long(sec) },
301: new StringBuffer(), null).toString(), Project.MSG_INFO);
302: }
303:
304: /**
305: * @param string
306: */
307: private void log(String message) {
308: task.log(message);
309: }
310:
311: public void setDispatcher(DispatchingVisitor dispatcher) {
312: this.dispatcher = dispatcher;
313: }
314: }
|