1 package net.sourceforge.pmd;
2
3 import net.sourceforge.pmd.swingui.event.ListenerList;
4 import net.sourceforge.pmd.swingui.event.PMDDirectoryRequestEvent;
5 import net.sourceforge.pmd.swingui.event.PMDDirectoryRequestEventListener;
6 import net.sourceforge.pmd.swingui.event.PMDDirectoryReturnedEvent;
7 import net.sourceforge.pmd.swingui.event.RuleSetEvent;
8 import net.sourceforge.pmd.swingui.event.RuleSetEventListener;
9
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.FileNotFoundException;
13 import java.io.FileOutputStream;
14 import java.io.FilenameFilter;
15 import java.io.IOException;
16 import java.text.MessageFormat;
17 import java.util.ArrayList;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Properties;
21
22
23 /***
24 * Defines and provides access to PMD's directory structure. The user defines the location
25 * of the root PMD directory, e.g., /users/userA/PMD. The PMD directory structure provides
26 * the following:
27 * <ul>
28 * <li>Organization to simplify PMD's access to files.</li>
29 * <li>Eliminates dependence of manually updating the Java classpath.</li>
30 * <li>Permits adding and removing rule sets without updating lists.</li>
31 * </ul>
32 * <pre>
33 * The directory structure and contents are the following:
34 * <code>
35 * PMD
36 * pmd.properties
37 * rulesets
38 * basic.xml
39 * design.xml
40 * import.xml
41 * com
42 * myCompany
43 * pmd
44 * rules
45 * myRule01.class
46 * myRule02.class
47 * myRule03.class
48 * net
49 * sourceforge
50 * pmd
51 * rules
52 * myNewExperimentalRule.class
53 * </code>
54 * </pre>
55 * The <b>PMD</b> directory is the root directory of all PMD files.
56 * <p>
57 * The <b>pmd.properties</b> file contains various information to be defined.
58 * <p>
59 * The <b>rulesets</b> directory contains the rule set files and rule class file directories.
60 * <p>
61 * A <b>rule set file</b> is a XML file that describes the rule set and its rules. This
62 * information is displayed and maintained in the PMD Viewer. The rule class files are called by PMD
63 * to perform the analysis.
64 * <p>
65 * All rule classes, other than the rule classes in pmd.jar, are stored in directory paths
66 * defined by each rule's class name. The Java classpath is appended with the rulesets
67 * directory so that the rule class and any supporting class files may be found.
68 * <p>
69 * <b>NOTE:</b> The user's home directory will contain a PMD directory with a user.preferences
70 * file. An entry in the user's preferences will be the path to the PMD root directory
71 * described above.
72 *
73 * @author Donald A. Leckie
74 * @since September 19, 2002
75 * @version $Revision: 1.13 $, $Date: 2003/03/14 19:03:44 $
76 */
77
78 public class PMDDirectory {
79
80 private String m_pmdDirectoryPath;
81 private String m_ruleSetsDirectoryPath;
82 private Properties m_properties;
83 private PMDDirectoryRequestEventHandler m_pmdDirectoryRequestEventHandler;
84 private RuleSetEventHandler m_ruleSetEventHandler;
85 private static PMDDirectory m_pmdDirectoryInstance;
86
87 // Constants
88 private final String PROPERTIES_FILE_NAME = "pmd.properties";
89
90 /***
91 ********************************************************************************
92 *
93 * Creates the information about the PMD directory structure that will be required
94 * for accessing the PMD files.
95 *
96 * @param pathToPMD The full path to the PMD directory, but excludes the PMD directory.
97 */
98 private PMDDirectory(String pathToPMD) throws PMDException {
99 String classpath;
100 String key;
101
102 m_pmdDirectoryRequestEventHandler = new PMDDirectoryRequestEventHandler();
103 m_ruleSetEventHandler = new RuleSetEventHandler();
104 ListenerList.addListener(m_pmdDirectoryRequestEventHandler);
105 ListenerList.addListener(m_ruleSetEventHandler);
106 m_pmdDirectoryPath = pathToPMD + File.separator + "PMD";
107 m_ruleSetsDirectoryPath = m_pmdDirectoryPath + File.separator + "rulesets";
108 key = "java.class.path";
109 classpath = System.getProperty(key);
110 classpath = classpath + ";" + m_ruleSetsDirectoryPath;
111 System.setProperty(key, classpath);
112 loadPropertiesFile();
113 }
114
115 /***
116 ********************************************************************************
117 *
118 * @param pathToPMD The full path to the PMD directory, but excludes the PMD directory.
119 */
120 public static final void open(String pathToPMD) throws PMDException {
121 m_pmdDirectoryInstance = new PMDDirectory(pathToPMD);
122 }
123
124 /***
125 ********************************************************************************
126 *
127 * @return
128 */
129 public static final PMDDirectory getDirectory() {
130 return m_pmdDirectoryInstance;
131 }
132
133 /***
134 ********************************************************************************
135 *
136 * Gets a rule set containing only the rule sets and rules to be included for running
137 * the analysis.
138 *
139 * @return A rule containing only included rules.
140 */
141 public RuleSet getIncludedRules(int lowestPriorityForAnalysis) throws PMDException {
142 RuleSet includedRules = new RuleSet();
143 Iterator ruleSetFiles = getRuleSetFiles().iterator();
144
145 while (ruleSetFiles.hasNext()) {
146 File ruleSetFile = (File) ruleSetFiles.next();
147 RuleSet ruleSet = getRuleSet(ruleSetFile, true);
148
149 if ((ruleSet != null) && ruleSet.include()) {
150 Iterator allRules = ruleSet.getRules().iterator();
151
152 while (allRules.hasNext()) {
153 Rule rule = (Rule) allRules.next();
154
155 if (rule.include()) {
156 if (rule.getPriority() <= lowestPriorityForAnalysis) {
157 includedRules.addRule(rule);
158 }
159 }
160 }
161 }
162 }
163
164 return includedRules;
165 }
166
167 /***
168 ********************************************************************************
169 *
170 * Gets the rule set for the given rule set file. All rules in the rule set file
171 * are stored in the rule set regardless of their <i>include</i> state.
172 *
173 * @param ruleSetFile The file of the desired rule set.
174 *
175 * @return A rule set containing all of its rules.
176 *
177 * @throws PMDException
178 */
179 public RuleSet getRuleSet(File ruleSetFile) throws PMDException {
180 return getRuleSet(ruleSetFile, false);
181 }
182
183 /***
184 ********************************************************************************
185 *
186 * Gets the rule set for the given rule set File. All rules in the rule set file
187 * are stored in the rule set according of their <i>include</i> state and the <i>onlyIfIncluded</i>
188 * flag.
189 *
190 * @param ruleSetFile The file of the desired rule set.
191 *
192 * @return A rule set containing all of its rules.
193 *
194 * @throws PMDException
195 */
196 public RuleSet getRuleSet(File ruleSetFile, boolean onlyIfIncluded) throws PMDException {
197 if (ruleSetFile == null) {
198 String message = "Rule set file parameter is missing.";
199 PMDException exception = new PMDException(message);
200 exception.fillInStackTrace();
201 throw exception;
202 }
203
204 FileInputStream inputStream = null;
205 RuleSet ruleSet = null;
206
207 try {
208 RuleSetReader reader;
209 inputStream = new FileInputStream(ruleSetFile);
210 reader = new RuleSetReader();
211 ruleSet = reader.read(inputStream, ruleSetFile.getName(), onlyIfIncluded);
212 } catch (FileNotFoundException exception) {
213 String template = "Rule set \"{0}\" was not found.";
214 String[] args = {ruleSetFile.getPath()};
215 String message = MessageFormat.format(template, args);
216 PMDException pmdException = new PMDException(message, exception);
217 pmdException.fillInStackTrace();
218 throw pmdException;
219 } finally {
220 if (inputStream != null) {
221 try {
222 inputStream.close();
223 } catch (IOException exception) {
224 }
225 }
226 }
227
228 return ruleSet;
229 }
230
231 /***
232 ********************************************************************************
233 *
234 * @return
235 */
236 private List getRuleSetFiles() {
237 List ruleSetFiles = new ArrayList();
238 File directory = new File(m_ruleSetsDirectoryPath);
239
240 if (directory.exists() == false) {
241 directory.mkdirs();
242 }
243
244 File[] files = directory.listFiles(new XMLFileNameFilter());
245
246 for (int n = 0; n < files.length; n++) {
247 ruleSetFiles.add(files[n]);
248 }
249
250 return ruleSetFiles;
251 }
252
253 /***
254 ********************************************************************************
255 *
256 * @return
257 */
258 public List getRegisteredRuleSets() {
259 List ruleSetList = new ArrayList();
260
261 try {
262 Iterator ruleSets = (new RuleSetFactory()).getRegisteredRuleSets();
263
264 while (ruleSets.hasNext()) {
265 RuleSet ruleSet;
266 Iterator rules;
267
268 ruleSet = (RuleSet) ruleSets.next();
269 ruleSet.setInclude(true);
270 rules = ruleSet.getRules().iterator();
271
272 while (rules.hasNext()) {
273 ((Rule) rules.next()).setInclude(true);
274 }
275
276 ruleSetList.add(ruleSet);
277 }
278 } catch (RuleSetNotFoundException exception) {
279 // This should not happen because the registered rule sets are resources in pmd.jar.
280 System.out.println(exception.getMessage());
281 }
282
283 return ruleSetList;
284 }
285
286 /***
287 ********************************************************************************
288 *
289 * @return
290 */
291 public List getRuleSets() throws PMDException {
292 List ruleSetList;
293 List ruleSetFilesList = getRuleSetFiles();
294
295 if (ruleSetFilesList.size() == 0) {
296 ruleSetList = getRegisteredRuleSets();
297 } else {
298 Iterator ruleSetFiles;
299
300 ruleSetList = new ArrayList();
301 ruleSetFiles = ruleSetFilesList.iterator();
302
303 while (ruleSetFiles.hasNext()) {
304 File ruleSetFile = (File) ruleSetFiles.next();
305 RuleSet ruleSet = getRuleSet(ruleSetFile);
306
307 ruleSetList.add(ruleSet);
308 }
309 }
310
311 return ruleSetList;
312 }
313
314 /***
315 ********************************************************************************
316 *
317 * @return
318 */
319 public String getPMDDirectoryPath() {
320 return m_pmdDirectoryPath;
321 }
322
323 /***
324 ********************************************************************************
325 *
326 * @return
327 */
328 public String getRuleSetsDirectoryPath() {
329 return m_ruleSetsDirectoryPath;
330 }
331
332 /***
333 ********************************************************************************
334 *
335 * @param ruleSetList
336 */
337 protected void saveRuleSets(List ruleSetList) {
338 Iterator ruleSets = ruleSetList.iterator();
339
340 while (ruleSets.hasNext()) {
341 RuleSet ruleSet = (RuleSet) ruleSets.next();
342 String ruleSetFileName = ruleSet.getFileName();
343 String path = m_ruleSetsDirectoryPath + File.separator + ruleSetFileName;
344 File file = new File(path);
345 FileOutputStream outputStream = null;
346
347 if (file.exists()) {
348 file.delete();
349 }
350
351 try {
352 RuleSetWriter writer;
353
354 outputStream = new FileOutputStream(file);
355 writer = new RuleSetWriter(outputStream);
356 writer.write(ruleSet);
357 } catch (FileNotFoundException exception) {
358 // Should not reach here because the rule set file has been deleted if it
359 // existed and the directories all exist.
360 exception = null;
361 } finally {
362 if (outputStream != null) {
363 try {
364 outputStream.close();
365 } catch (IOException exception) {
366 exception = null;
367 }
368 }
369 }
370 }
371 }
372
373 /***
374 ********************************************************************************
375 *
376 * @param pathToPMD
377 */
378 private void loadPropertiesFile() throws PMDException {
379 String propertiesFileName;
380 FileInputStream inputStream;
381
382 propertiesFileName = m_pmdDirectoryPath + File.separator + PROPERTIES_FILE_NAME;
383 m_properties = new Properties();
384 inputStream = null;
385
386 try {
387 File file = new File(propertiesFileName);
388
389 if (file.exists() == false) {
390 File directory = file.getParentFile();
391
392 directory.mkdirs();
393 file.createNewFile();
394 }
395
396 inputStream = new FileInputStream(propertiesFileName);
397 m_properties.load(inputStream);
398 } catch (FileNotFoundException exception) {
399 String template = "Could not find the file \"{0}\".";
400 String[] args = {propertiesFileName};
401 String message = MessageFormat.format(template, args);
402 PMDException pmdException = new PMDException(message, exception);
403 pmdException.fillInStackTrace();
404 throw pmdException;
405 } catch (IOException exception) {
406 String template = "Unable to read the file \"{0}\".";
407 String[] args = {propertiesFileName};
408 String message = MessageFormat.format(template, args);
409 PMDException pmdException = new PMDException(message, exception);
410 pmdException.fillInStackTrace();
411 throw pmdException;
412 } finally {
413 if (inputStream != null) {
414 try {
415 inputStream.close();
416 } catch (IOException exception) {
417 exception = null;
418 }
419 }
420 }
421 }
422
423 /***
424 ********************************************************************************
425 *
426 */
427 public void savePropertiesFile() throws PMDException {
428 FileOutputStream outputStream = null;
429 String propertiesFileName = m_pmdDirectoryPath + File.separator + PROPERTIES_FILE_NAME;
430 File file = new File(propertiesFileName);
431 if (file.exists()) {
432 file.delete();
433 }
434
435 try {
436 m_properties.store(outputStream, null);
437 } catch (FileNotFoundException exception) {
438 String template = "Could not find the file \"{0}\".";
439 String[] args = {propertiesFileName};
440 String message = MessageFormat.format(template, args);
441 PMDException pmdException = new PMDException(message, exception);
442 pmdException.fillInStackTrace();
443 throw pmdException;
444 } catch (IOException exception) {
445 String template = "Unable to read the file \"{0}\".";
446 String[] args = {propertiesFileName};
447 String message = MessageFormat.format(template, args);
448 PMDException pmdException = new PMDException(message, exception);
449 pmdException.fillInStackTrace();
450 throw pmdException;
451 } finally {
452 if (outputStream != null) {
453 try {
454 outputStream.close();
455 } catch (IOException exception) {
456 exception = null;
457 }
458 }
459 }
460 }
461
462 /***
463 *******************************************************************************
464 *******************************************************************************
465 *******************************************************************************
466 */
467 private class RuleSetEventHandler implements RuleSetEventListener {
468
469 /***
470 ***************************************************************************
471 *
472 * @param event
473 */
474 public void saveRuleSets(RuleSetEvent event) {
475 List ruleSetList = event.getRuleSetList();
476 PMDDirectory.this.saveRuleSets(ruleSetList);
477 }
478 }
479
480 /***
481 *******************************************************************************
482 *******************************************************************************
483 *******************************************************************************
484 */
485 private class PMDDirectoryRequestEventHandler implements PMDDirectoryRequestEventListener {
486
487 /***
488 ***************************************************************************
489 *
490 * @param event
491 */
492 public void requestRuleSetPath(PMDDirectoryRequestEvent event) {
493 PMDDirectoryReturnedEvent.notifyReturnedRuleSetPath(this, getRuleSetsDirectoryPath());
494 }
495
496 /***
497 ***************************************************************************
498 *
499 * @param event
500 */
501 public void requestAllRuleSets(PMDDirectoryRequestEvent event) throws PMDException {
502 PMDDirectoryReturnedEvent.notifyReturnedAllRuleSets(this, getRuleSets());
503 }
504
505 /***
506 ***************************************************************************
507 *
508 * @param event
509 */
510 public void requestDefaultRuleSets(PMDDirectoryRequestEvent event) {
511 PMDDirectoryReturnedEvent.notifyReturnedDefaultRuleSets(this, getRegisteredRuleSets());
512 }
513
514 /***
515 ***************************************************************************
516 *
517 * @param event
518 */
519 public void requestIncludedRules(PMDDirectoryRequestEvent event) throws PMDException {
520 int priority = event.getLowestPriorityForAnalysis();
521 PMDDirectoryReturnedEvent.notifyReturnedIncludedRules(this, getIncludedRules(priority));
522 }
523 }
524
525 /***
526 *******************************************************************************
527 *******************************************************************************
528 *******************************************************************************
529 */
530 private class XMLFileNameFilter implements FilenameFilter {
531
532 /***
533 ***************************************************************************
534 *
535 * @param directory
536 * @param fileName
537 *
538 * @return
539 */
540 public boolean accept(File directory, String fileName) {
541 return fileName.toLowerCase().endsWith(".xml");
542 }
543 }
544 }
This page was automatically generated by Maven