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.util.Collection;
027:
028: import org.apache.tools.ant.BuildException;
029: import org.apache.tools.ant.Project;
030: import org.hammurapi.results.AggregatedResults;
031: import org.hammurapi.results.ResultsFactory;
032:
033: import com.pavelvlasov.jsel.Repository;
034: import com.pavelvlasov.review.SourceMarker;
035: import com.pavelvlasov.util.DispatchingVisitor;
036: import com.pavelvlasov.util.OrderedTarget;
037: import com.pavelvlasov.util.VisitorExceptionSink;
038: import com.pavelvlasov.util.VisitorStack;
039: import com.pavelvlasov.util.VisitorStackSource;
040:
041: /**
042: * Pool of review threads. Delegates review work to threads.
043: * @author Pavel Vlasov
044: * @version $Revision: 1.8 $
045: */
046: public class SimpleReviewEngine implements VisitorStackSource {
047: private DispatchingVisitor visitor;
048:
049: public SimpleReviewEngine(Collection inspectors,
050: final HammurapiTask task) {
051: VisitorExceptionSink esink = new VisitorExceptionSink() {
052:
053: public void consume(DispatchingVisitor dispatcher,
054: Object visitor, Method method, Object visitee,
055: Exception e) {
056: task.log("WARN: Exception in " + visitee,
057: Project.MSG_WARN);
058: e.printStackTrace();
059:
060: AggregatedResults results = ResultsFactory
061: .getThreadResults();
062: if (task.failOnFirstException) {
063: throw new BuildException("Cause: " + e, e);
064: } else if (results == null
065: || e instanceof HammurapiNonConsumableException) {
066: task.setHadExceptions();
067: } else {
068: results
069: .addWarning(new SimpleViolation(
070: visitee instanceof SourceMarker ? (SourceMarker) visitee
071: : null, "Exception " + e,
072: null));
073: }
074:
075: if (task.evictBadInspectors) {
076: dispatcher.remove(visitor);
077: if (visitor instanceof Inspector) {
078: String name = ((Inspector) visitor)
079: .getContext().getDescriptor().getName();
080: results
081: .addWarning(new SimpleViolation(
082: visitee instanceof SourceMarker ? (SourceMarker) visitee
083: : null,
084: "Inspector "
085: + name
086: + " threw "
087: + e
088: + " and has been disabled",
089: null));
090: }
091: }
092: }
093: };
094: visitor = new DispatchingVisitor(inspectors, esink,
095: getListener(task));
096: }
097:
098: public void review(Repository repository) {
099: repository.accept(visitor);
100: }
101:
102: protected static DispatchingVisitor.Listener getListener(
103: final HammurapiTask task) {
104: if (task.getDebugType() == null) {
105: return null;
106: }
107:
108: return new DispatchingVisitor.Listener() {
109: private boolean isEnabled = true;
110: private Class type;
111:
112: private void log(String message) {
113: task.log(message, Project.MSG_INFO);
114: }
115:
116: boolean isListeningFor(Object o) {
117: if (isEnabled) {
118: if (type == null) {
119: try {
120: type = o.getClass().getClassLoader()
121: .loadClass(task.getDebugType());
122: } catch (ClassNotFoundException e) {
123: task.log(e.toString(), Project.MSG_WARN);
124: isEnabled = false;
125: return false;
126: }
127: }
128: return type.isAssignableFrom(o.getClass());
129:
130: }
131:
132: return false;
133: }
134:
135: public void onInvocationRegistration(Object target,
136: Method method) {
137: log("\tDispatch invocaton registration");
138: log("\t\tTarget type: " + target.getClass());
139: log("\t\tTarget method: " + method);
140: }
141:
142: public void onInvocation(Object target, Method method,
143: Object visitable) {
144: if (isListeningFor(visitable)) {
145: log("Dispatch invocation");
146: log("\tTarget type: " + target.getClass());
147: log("\tTarget method: " + method);
148: log("\tVisitable type: " + visitable.getClass());
149: log("\tVisitable: " + visitable);
150: }
151: }
152:
153: public void onVisit(Object target) {
154: if (isListeningFor(target)) {
155: log("Dispatch visit");
156: log("\tVisitable type: " + target.getClass());
157: log("\tVisitable: " + target);
158: }
159: }
160:
161: public void onLeave(Object target) {
162: if (isListeningFor(target)) {
163: log("Dispatch leave");
164: log("\tVisitable type: " + target.getClass());
165: log("\tVisitable: " + target);
166: }
167: }
168:
169: public void onTargetRegistration(Object target) {
170: log("Dispatch type registration");
171: log("\tTarget type: " + target.getClass());
172: if (target instanceof OrderedTarget) {
173: log("\tOrder: "
174: + ((OrderedTarget) target).getOrder());
175: }
176: }
177:
178: public void noInvocationsWarning(Object target) {
179: log("WARNING: No invocations for type: "
180: + target.getClass());
181: }
182:
183: public void onFilterRegistration(Method filter,
184: Method target) {
185: log("\tFilter registration");
186: log("\t\tFilter method: " + filter);
187: log("\t\tTarget method: " + target);
188: }
189: };
190: }
191:
192: public VisitorStack getVisitorStack() {
193: return visitor.getVisitorStack();
194: }
195:
196: public DispatchingVisitor getVisitor() {
197: return visitor;
198: }
199: }
|