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.lang.reflect.Method;
026: import java.sql.SQLException;
027: import java.util.Collection;
028:
029: import org.apache.tools.ant.BuildException;
030: import org.apache.tools.ant.Project;
031: import org.hammurapi.results.AggregatedResults;
032: import org.hammurapi.results.ResultsFactory;
033:
034: import com.pavelvlasov.jsel.CompilationUnit;
035: import com.pavelvlasov.review.SourceMarker;
036: import com.pavelvlasov.util.DispatchingVisitor;
037: import com.pavelvlasov.util.OrderedTarget;
038: import com.pavelvlasov.util.VisitorExceptionSink;
039: import com.pavelvlasov.util.VisitorStack;
040: import com.pavelvlasov.util.VisitorStackSource;
041:
042: /**
043: * Pool of review threads. Delegates review work to threads.
044: * @author Pavel Vlasov
045: * @version $Revision: 1.3 $
046: */
047: public class QuickReviewEngine implements VisitorStackSource {
048: private DispatchingVisitor visitor;
049: private QuickResultsCollector collector;
050: private QuickHammurapiTask task;
051:
052: /**
053: * @param task
054: * @param rules
055: * @param poolSize If > 1 then multithreaded processing will be used.
056: * @throws SQLException
057: */
058: public QuickReviewEngine(Collection inspectors,
059: final QuickHammurapiTask task,
060: QuickResultsCollector collector) throws SQLException {
061: super ();
062: VisitorExceptionSink esink = new VisitorExceptionSink() {
063:
064: public void consume(final DispatchingVisitor dispatcher,
065: final Object visitor, final Method method,
066: final Object visitee, final Exception e) {
067: task.log("WARN: Exception in " + visitee,
068: Project.MSG_WARN);
069: e.printStackTrace();
070:
071: AggregatedResults results = ResultsFactory
072: .getThreadResults();
073: if (task.failOnFirstException) {
074: throw new BuildException("Cause: " + e, e);
075: } else if (results == null
076: || e instanceof HammurapiNonConsumableException) {
077: task.setHadExceptions();
078: } else {
079: results
080: .addWarning(new SimpleViolation(
081: visitee instanceof SourceMarker ? (SourceMarker) visitee
082: : null, "Exception " + e,
083: null));
084: }
085:
086: if (task.evictBadInspectors) {
087: dispatcher.remove(visitor);
088: }
089: }
090: };
091: visitor = new DispatchingVisitor(inspectors, esink,
092: getListener(task));
093: this .collector = collector;
094: collector.getEngine().init();
095: this .task = task;
096: }
097:
098: public void review(CompilationUnit compilationUnit)
099: throws SQLException {
100: if (!task.force) {
101: if (task.forceOnWarnings) {
102: Integer id = collector.getEngine()
103: .getResultByNameSizeChecksumNoWarnings(
104: compilationUnit.getPackage().getName(),
105: compilationUnit.getName(),
106: compilationUnit.getSize(),
107: compilationUnit.getCheckSum());
108:
109: if (id != null) {
110: collector.getEngine().setUntouched(id.intValue());
111: return;
112: }
113: } else {
114: Integer id = collector.getEngine()
115: .getResultByNameSizeChecksum(
116: compilationUnit.getPackage().getName(),
117: compilationUnit.getName(),
118: compilationUnit.getSize(),
119: compilationUnit.getCheckSum());
120:
121: if (id != null) {
122: collector.getEngine().setUntouched(id.intValue());
123: return;
124: }
125: }
126: }
127:
128: compilationUnit.accept(visitor);
129: }
130:
131: protected static DispatchingVisitor.Listener getListener(
132: final QuickHammurapiTask task) {
133: if (task.getDebugType() == null) {
134: return null;
135: } else {
136: return new DispatchingVisitor.Listener() {
137: private boolean isEnabled = true;
138: private Class type;
139:
140: private void log(String message) {
141: task.log(message, Project.MSG_INFO);
142: }
143:
144: boolean isListeningFor(Object o) {
145: if (isEnabled) {
146: if (type == null) {
147: try {
148: type = o.getClass().getClassLoader()
149: .loadClass(task.getDebugType());
150: } catch (ClassNotFoundException e) {
151: task
152: .log(e.toString(),
153: Project.MSG_WARN);
154: isEnabled = false;
155: return false;
156: }
157: }
158: return type.isAssignableFrom(o.getClass());
159:
160: } else {
161: return false;
162: }
163: }
164:
165: public void onInvocationRegistration(Object target,
166: Method method) {
167: log("\tDispatch invocaton registration");
168: log("\t\tTarget type: " + target.getClass());
169: log("\t\tTarget method: " + method);
170: }
171:
172: public void onInvocation(Object target, Method method,
173: Object visitable) {
174: if (isListeningFor(visitable)) {
175: log("Dispatch invocation");
176: log("\tTarget type: " + target.getClass());
177: log("\tTarget method: " + method);
178: log("\tVisitable type: " + visitable.getClass());
179: log("\tVisitable: " + visitable);
180: }
181: }
182:
183: public void onVisit(Object target) {
184: if (isListeningFor(target)) {
185: log("Dispatch visit");
186: log("\tVisitable type: " + target.getClass());
187: log("\tVisitable: " + target);
188: }
189: }
190:
191: public void onLeave(Object target) {
192: if (isListeningFor(target)) {
193: log("Dispatch leave");
194: log("\tVisitable type: " + target.getClass());
195: log("\tVisitable: " + target);
196: }
197: }
198:
199: public void onTargetRegistration(Object target) {
200: log("Dispatch type registration");
201: log("\tTarget type: " + target.getClass());
202: if (target instanceof OrderedTarget) {
203: log("\tOrder: "
204: + ((OrderedTarget) target).getOrder());
205: }
206: }
207:
208: public void noInvocationsWarning(Object target) {
209: log("WARNING: No invocations for type: "
210: + target.getClass());
211: }
212:
213: public void onFilterRegistration(Method filter,
214: Method target) {
215: log("\tFilter registration");
216: log("\t\tFilter method: " + filter);
217: log("\t\tTarget method: " + target);
218: }
219: };
220: }
221: }
222:
223: public VisitorStack getVisitorStack() {
224: return visitor.getVisitorStack();
225: }
226:
227: public DispatchingVisitor getVisitor() {
228: return visitor;
229: }
230:
231: }
|