View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.processor;
5   
6   import java.io.BufferedInputStream;
7   import java.io.IOException;
8   import java.io.InputStream;
9   import java.util.List;
10  import java.util.concurrent.Callable;
11  import java.util.concurrent.ExecutorService;
12  import java.util.logging.Level;
13  import java.util.logging.Logger;
14  
15  import net.sourceforge.pmd.PMDConfiguration;
16  import net.sourceforge.pmd.PMD;
17  import net.sourceforge.pmd.PMDException;
18  import net.sourceforge.pmd.Report;
19  import net.sourceforge.pmd.RuleContext;
20  import net.sourceforge.pmd.RuleSetFactory;
21  import net.sourceforge.pmd.RuleSets;
22  import net.sourceforge.pmd.renderers.Renderer;
23  import net.sourceforge.pmd.util.datasource.DataSource;
24  
25  public class PmdRunnable extends PMD implements Callable<Report> {
26  
27  	private static final Logger LOG = Logger.getLogger(PmdRunnable.class.getName());
28  
29  	private final ExecutorService executor;
30  	private final DataSource dataSource;
31  	private final String fileName;
32  	private final List<Renderer> renderers;
33  
34  	public PmdRunnable(ExecutorService executor,
35  			PMDConfiguration configuration, DataSource dataSource,
36  			String fileName, List<Renderer> renderers) {
37  		super(configuration);
38  		this.executor = executor;
39  		this.dataSource = dataSource;
40  		this.fileName = fileName;
41  		this.renderers = renderers;
42  	}
43  
44  	// If we ever end up having a ReportUtil class, this method should be moved there...
45  	private static void addError(Report report, Exception ex, String fileName) {
46  		report.addError(
47  				new Report.ProcessingError(ex.getMessage(),
48  				fileName)
49  				);
50  	}
51  
52  	private void addErrorAndShutdown(Report report, Exception e, String errorMessage) {
53  		// unexpected exception: log and stop executor service
54  		LOG.log(Level.FINE, errorMessage, e);
55  		addError(report, e, fileName);
56  		executor.shutdownNow();
57  	}
58  	
59  	public Report call() {
60  		PmdThread thread = (PmdThread) Thread.currentThread();
61  
62  		RuleContext ctx = thread.getRuleContext();
63  		RuleSets rs = thread.getRuleSets(configuration.getRuleSets(), configuration.getPmdRuleSets());
64  		configuration.setPmdRuleSets(rs);
65  
66  		Report report = setupReport(rs, ctx, fileName);
67  		
68  		if (LOG.isLoggable(Level.FINE)) {
69  			LOG.fine("Processing " + ctx.getSourceCodeFilename());
70  		}
71  		for (Renderer r : renderers) {
72  			r.startFileAnalysis(dataSource);
73  		}
74  
75  		try {
76  			InputStream stream = new BufferedInputStream(
77  					dataSource.getInputStream());
78  			ctx.setLanguageVersion(null);
79  			this.getSourceCodeProcessor().processSourceCode(stream, rs, ctx);
80  		} catch (PMDException pmde) {
81  		    if (LOG.isLoggable(Level.FINE)) {
82  			LOG.log(Level.FINE, "Error while processing file: "+fileName, pmde.getCause());
83  		    }
84  			addError(report, pmde, fileName);
85  		} catch (IOException ioe) {
86  			addErrorAndShutdown(report, ioe, "IOException during processing of "+ fileName );
87  
88  		} catch (RuntimeException re) {
89  			addErrorAndShutdown(report, re,"RuntimeException during processing of " + fileName);
90  		}
91  		return report;
92  	}
93  	
94  	private static class PmdThread extends Thread {
95  
96  		public PmdThread(int id, Runnable r, RuleSetFactory ruleSetFactory,
97  				RuleContext ctx) {
98  			super(r, "PmdThread " + id);
99  			this.id = id;
100 			context = new RuleContext(ctx);
101 			this.ruleSetFactory = ruleSetFactory;
102 		}
103 
104 		private final int id;
105 		private RuleContext context;
106 		private RuleSets rulesets;
107 		private final RuleSetFactory ruleSetFactory;
108 
109 		public RuleContext getRuleContext() {
110 			return context;
111 		}
112 
113 		public RuleSets getRuleSets(String rsList, RuleSets ruleSets) {
114 			if (rulesets == null) {
115 				try {
116 					rulesets = ruleSetFactory.createRuleSets(rsList, ruleSets);
117 				} catch (Exception e) {
118 					e.printStackTrace();
119 				}
120 			}
121 			return rulesets;
122 		}
123 
124 		@Override
125 		public String toString() {
126 			return "PmdThread " + id;
127 		}
128 	}
129 
130 	public static Thread createThread(int id, Runnable r,
131 			RuleSetFactory ruleSetFactory, RuleContext ctx) {
132 		return new PmdThread(id, r,ruleSetFactory, ctx);
133 	}
134 }