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.File;
026: import java.io.FileReader;
027: import java.io.InputStream;
028: import java.io.Reader;
029: import java.lang.reflect.Method;
030: import java.net.URL;
031: import java.net.URLClassLoader;
032: import java.sql.SQLException;
033: import java.util.Collection;
034: import java.util.Date;
035: import java.util.HashSet;
036: import java.util.Iterator;
037: import java.util.Set;
038:
039: import org.hammurapi.results.Annotation;
040:
041: import com.pavelvlasov.config.ConfigurationException;
042: import com.pavelvlasov.jsel.CompilationUnit;
043: import com.pavelvlasov.jsel.JselException;
044: import com.pavelvlasov.jsel.impl.CompilationUnitImpl;
045: import com.pavelvlasov.logging.Logger;
046: import com.pavelvlasov.persistence.CompositeStorage;
047: import com.pavelvlasov.persistence.FileStorage;
048: import com.pavelvlasov.persistence.MemoryStorage;
049: import com.pavelvlasov.review.Signed;
050: import com.pavelvlasov.review.SourceMarker;
051: import com.pavelvlasov.util.ClassResourceLoader;
052: import com.pavelvlasov.util.DispatchingVisitor;
053: import com.pavelvlasov.util.VisitorExceptionSink;
054: import com.pavelvlasov.util.VisitorStack;
055: import com.pavelvlasov.util.VisitorStackSource;
056:
057: /**
058: * This class is to be used by IDE plugins
059: * @author Pavel Vlasov
060: * @version $Revision: 1.8 $
061: */
062: public class Reviewer {
063:
064: private Logger logger;
065: private InspectorSet inspectorSet;
066: private WaiverSet waiverSet = new WaiverSet();
067: private CompositeStorage storage = new CompositeStorage();
068: private DispatchingVisitor visitor;
069: private SessionImpl session = new SessionImpl();
070: private int tabSize = 8;
071:
072: private class ReviewerInspectorContext extends InspectorContextBase {
073:
074: public ReviewerInspectorContext(InspectorDescriptor descriptor,
075: Logger logger, VisitorStackSource visitorStackSource) {
076: super (descriptor, logger, visitorStackSource, session);
077: }
078:
079: /**
080: *
081: * @param source
082: * @param message
083: */
084: public void reportViolation(SourceMarker source, String message) {
085: Violation violation = new SimpleViolation(detach(source),
086: message, descriptor);
087: addViolation(violation);
088: }
089:
090: public void annotate(Annotation annotation) {
091: addAnnotation(annotation);
092: }
093:
094: public void addMetric(SourceMarker source, String name,
095: double value) {
096: // Ignore
097: }
098:
099: /**
100: * Report warning
101: * @param source
102: * @param message
103: */
104: public void warn(SourceMarker source, String message) {
105: Violation violation = new SimpleViolation(detach(source),
106: message, descriptor);
107: addWarning(violation);
108: if (source == null) {
109: System.err.println("WARNING: " + message);
110: } else {
111: System.err.println("WARNING at "
112: + source.getSourceURL() + " "
113: + source.getLine() + ":" + source.getColumn()
114: + " : " + message);
115: }
116: }
117:
118: /**
119: * Report warning
120: * @param source
121: */
122: public void warn(SourceMarker source, Throwable th) {
123: Violation violation = new SimpleViolation(detach(source),
124: th.toString(), descriptor);
125: addWarning(violation);
126: // TODO better warning handling here
127: if (source == null) {
128: System.err.println("WARNING: " + th);
129: } else {
130: System.err.println("WARNING at "
131: + source.getSourceURL() + " "
132: + source.getLine() + ":" + source.getColumn()
133: + " : " + th);
134: }
135: th.printStackTrace();
136: }
137:
138: /**
139: * Creates a waiver for inspector with a given key
140: * @param inspectorKey
141: */
142: public void waive(Signed signed, final String inspectorKey) {
143: final String iName = descriptor
144: .getWaivedInspectorName(inspectorKey);
145: if (iName == null) {
146: warn(
147: signed instanceof SourceMarker ? (SourceMarker) signed
148: : null, descriptor.getName()
149: + ": Inspector with key '"
150: + inspectorKey + "' not found.");
151: } else {
152: final String signature = signed == null ? null : signed
153: .getSignature();
154: final Set signatures = new HashSet();
155: if (signature != null) {
156: signatures.add(signature);
157: }
158:
159: if (Reviewer.this .logger != null) {
160: Reviewer.this .logger.debug(this , "Inspector "
161: + getDescriptor().getName()
162: + " autowaives " + iName + " at "
163: + signature);
164: }
165:
166: Waiver waiver = new Waiver() {
167: boolean active = true;
168:
169: public String getInspectorName() {
170: return iName;
171: }
172:
173: public boolean waive(Violation violation,
174: boolean peek) {
175: if (iName.equals(violation.getDescriptor()
176: .getName())) {
177: if (signature == null) {
178: return true;
179: } else if (violation.getSource() instanceof Signed
180: && signature
181: .equals(((Signed) violation
182: .getSource())
183: .getSignature())) {
184: if (!peek) {
185: active = false;
186: }
187: return true;
188: }
189: }
190: return false;
191: }
192:
193: public Date getExpirationDate() {
194: return null;
195: }
196:
197: public String getReason() {
198: return descriptor.getWaiveReason(inspectorKey);
199: }
200:
201: public boolean isActive() {
202: return active;
203: }
204:
205: public Collection getSignatures() {
206: return signatures;
207: }
208: };
209: waiverSet.addWaiver(waiver, date);
210: }
211: }
212: }
213:
214: public Reviewer(final Logger logger, boolean embeddedInspectors,
215: Collection inspectors, Collection waivers)
216: throws HammurapiException {
217: this .logger = logger;
218: final VisitorStack[] visitorStack = { null };
219:
220: final VisitorStackSource delegatingVisitorStackSource = new VisitorStackSource() {
221:
222: public VisitorStack getVisitorStack() {
223: return visitorStack[0];
224: }
225: };
226:
227: inspectorSet = new InspectorSet(new InspectorContextFactory() {
228: public InspectorContext newContext(
229: final InspectorDescriptor descriptor,
230: final Logger logger) {
231: return new ReviewerInspectorContext(descriptor, logger,
232: delegatingVisitorStackSource);
233: }
234: }, logger);
235:
236: if (embeddedInspectors) {
237: InputStream inspectorStream = HammurapiTask.class
238: .getResourceAsStream("inspectors.xml");
239: if (inspectorStream == null) {
240: throw new HammurapiException(
241: "Cannot load embedded inspectors");
242: }
243:
244: DomInspectorSource source = new DomInspectorSource(
245: inspectorStream, "Hammurapi.jar");
246: source.loadInspectors(inspectorSet);
247: }
248:
249: if (inspectors != null) {
250: Iterator it = inspectors.iterator();
251: while (it.hasNext()) {
252: try {
253: inspectorSet.addDescriptor((InspectorDescriptor) it
254: .next());
255: } catch (ConfigurationException e) {
256: throw new HammurapiException(e);
257: }
258: }
259: }
260:
261: if (waivers != null) {
262: Date now = new Date();
263: Iterator it = waivers.iterator();
264: while (it.hasNext()) {
265: waiverSet.addWaiver((Waiver) it.next(), now);
266: }
267: }
268:
269: storage.addStorage("file", new FileStorage(new File(System
270: .getProperties().getProperty("java.io.tmpdir"))));
271: storage.addStorage("memory", new MemoryStorage());
272: session.setStorage(storage);
273:
274: try {
275: Collection ic = inspectorSet.getInspectors();
276:
277: visitor = new DispatchingVisitor(ic,
278: new VisitorExceptionSink() {
279: public void consume(
280: DispatchingVisitor dispatcher,
281: Object visitor, Method method,
282: Object visitee, Exception e) {
283: if (logger != null) {
284: logger.warn(visitee, "Exception: " + e);
285: }
286:
287: e.printStackTrace();
288:
289: getRequest()
290: .onWarning(
291: new SimpleViolation(
292: visitee instanceof SourceMarker ? (SourceMarker) visitee
293: : null,
294: "Exception: " + e,
295: null));
296: }
297: }, null);
298: session.setInspectors(inspectorSet);
299: visitorStack[0] = visitor.getVisitorStack();
300: } catch (ConfigurationException e) {
301: throw new HammurapiException(e);
302: }
303:
304: session.setVisitor(visitor);
305: }
306:
307: public Reviewer(final Logger logger, boolean embeddedInspectors,
308: InspectorSource inspectorSource, WaiverSource waiverSource)
309: throws HammurapiException {
310: this .logger = logger;
311: final VisitorStack[] visitorStack = { null };
312:
313: final VisitorStackSource delegatingVisitorStackSource = new VisitorStackSource() {
314:
315: public VisitorStack getVisitorStack() {
316: return visitorStack[0];
317: }
318: };
319:
320: inspectorSet = new InspectorSet(new InspectorContextFactory() {
321: public InspectorContext newContext(
322: final InspectorDescriptor descriptor,
323: final Logger logger) {
324: return new ReviewerInspectorContext(descriptor, logger,
325: delegatingVisitorStackSource);
326: }
327: }, logger);
328:
329: if (embeddedInspectors) {
330: ClassResourceLoader crl = new ClassResourceLoader(
331: TaskBase.class);
332: InputStream inspectorStream = crl.getResourceAsStream(null,
333: null, "xml");
334: if (inspectorStream == null) {
335: throw new HammurapiException(
336: "Cannot load embedded inspectors");
337: }
338:
339: DomInspectorSource source = new DomInspectorSource(
340: inspectorStream, "Hammurapi.jar");
341: source.loadInspectors(inspectorSet);
342: }
343:
344: if (inspectorSource != null) {
345: inspectorSource.loadInspectors(inspectorSet);
346: }
347:
348: if (waiverSource != null) {
349: Date now = new Date();
350: waiverSource.loadWaivers(waiverSet, now);
351: }
352:
353: storage.addStorage("file", new FileStorage(new File(System
354: .getProperties().getProperty("java.io.tmpdir"))));
355: storage.addStorage("memory", new MemoryStorage());
356: session.setStorage(storage);
357:
358: try {
359: Collection ic = inspectorSet.getInspectors();
360:
361: visitor = new DispatchingVisitor(ic,
362: new VisitorExceptionSink() {
363: public void consume(
364: DispatchingVisitor dispatcher,
365: Object visitor, Method method,
366: Object visitee, Exception e) {
367: if (logger != null) {
368: logger.warn(visitee, "Exception: " + e);
369: }
370:
371: e.printStackTrace();
372:
373: getRequest()
374: .onWarning(
375: new SimpleViolation(
376: visitee instanceof SourceMarker ? (SourceMarker) visitee
377: : null,
378: "Exception: " + e,
379: null));
380: }
381: }, null);
382: session.setInspectors(inspectorSet);
383: visitorStack[0] = visitor.getVisitorStack();
384: } catch (ConfigurationException e) {
385: throw new HammurapiException(e);
386: }
387:
388: session.setVisitor(visitor);
389: }
390:
391: private ThreadLocal requestTL = new ThreadLocal();
392:
393: private ReviewRequest getRequest() {
394: return (ReviewRequest) requestTL.get();
395: }
396:
397: public void process(final ReviewRequest request)
398: throws HammurapiException {
399: requestTL.set(request);
400: try {
401: CompilationUnit cu = new CompilationUnitImpl(request
402: .getSource(), null, request.getRootDir(), request
403: .getName(), tabSize, request.getClassLoader(),
404: logger);
405: cu.accept(visitor);
406: } catch (JselException e) {
407: throw new HammurapiException(e);
408: } finally {
409: requestTL.set(null);
410: }
411: }
412:
413: private void addViolation(Violation violation) {
414: getRequest().onViolation(violation);
415: }
416:
417: /**
418: * @param annotation
419: */
420: private void addAnnotation(Annotation annotation) {
421: // Annotations are ignored
422: }
423:
424: /**
425: * @param violation
426: */
427: private void addWarning(Violation violation) {
428: getRequest().onWarning(violation);
429: }
430:
431: public void shutdown() throws HammurapiException {
432: try {
433: session.shutdown();
434: } catch (SQLException e) {
435: throw new HammurapiException("Cannot shutdown session", e);
436: }
437: }
438:
439: public static void main(String[] arg) throws Exception {
440: final File source = new File(
441: "..\\UmlApi\\src\\com\\pavelvlasov\\uml\\Operation.java");
442: System.out.println(source.getAbsolutePath());
443: ClassLoader classLoader = new URLClassLoader(
444: new URL[] { new File("..\\UmlApi\\bin").toURL() },
445: Reviewer.class.getClassLoader());
446:
447: final Reader sr = new FileReader(source);
448: Reviewer reviewer = new Reviewer(null, true,
449: (InspectorSource) null, null);
450: reviewer.process(new ReviewRequestBase(classLoader) {
451:
452: public Reader getSource() {
453: return sr;
454: }
455:
456: public String getName() {
457: return "com/pavelvlasov/uml/Operation.java";
458: }
459:
460: public void onViolation(Violation violation) {
461: System.out.println("VIOLATION: "
462: + violation.getDescriptor().getName() + ": "
463: + violation.getMessage());
464: }
465:
466: public void onWarning(Violation warning) {
467: System.out.println("WARNING: " + warning.getMessage());
468: }
469:
470: public File getRootDir() {
471: return new File("..\\UmlApi\\src");
472: }
473: });
474: }
475:
476: /**
477: * @return Returns the tabSize.
478: */
479: public int getTabSize() {
480: return tabSize;
481: }
482:
483: /**
484: * @param tabSize The tabSize to set.
485: */
486: public void setTabSize(int tabSize) {
487: this.tabSize = tabSize;
488: }
489: }
|