1 /** 2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html 3 */ 4 package net.sourceforge.pmd; 5 6 import java.io.File; 7 import java.util.Map; 8 import java.util.concurrent.ConcurrentHashMap; 9 10 import net.sourceforge.pmd.lang.LanguageVersion; 11 12 /** 13 * The RuleContext provides access to Rule processing state. This information 14 * includes the following global information: 15 * <ul> 16 * <li>The Report to which Rule Violations are sent.</li> 17 * <li>Named attributes.</li> 18 * </ul> 19 * As well as the following source file specific information: 20 * <ul> 21 * <li>A File for the source file.</li> 22 * <li>A String for the name of the source file.</li> 23 * <li>The Language Version of the source file.</li> 24 * </ul> 25 * It is <strong>required</strong> that all source file specific options 26 * be set between calls to difference source files. Failure to do so, may 27 * result in undefined behavior. 28 */ 29 public class RuleContext { 30 31 private Report report = new Report(); 32 private File sourceCodeFile; 33 private String sourceCodeFilename; 34 private LanguageVersion languageVersion; 35 private final Map<String, Object> attributes; 36 private boolean ignoreExceptions = true; 37 38 /** 39 * Default constructor. 40 */ 41 public RuleContext() { 42 attributes = new ConcurrentHashMap<String, Object>(); 43 } 44 45 /** 46 * Constructor which shares attributes and report listeners with the given RuleContext. 47 * @param ruleContext the context from which the values are shared 48 */ 49 public RuleContext(RuleContext ruleContext) { 50 this.attributes = ruleContext.attributes; 51 this.report.addSynchronizedListeners(ruleContext.getReport().getSynchronizedListeners()); 52 } 53 54 /** 55 * Get the Report to which Rule Violations are sent. 56 * @return The Report. 57 */ 58 public Report getReport() { 59 return report; 60 } 61 62 /** 63 * Set the Report to which Rule Violations are sent. 64 * @param report The Report. 65 */ 66 public void setReport(Report report) { 67 this.report = report; 68 } 69 70 /** 71 * Get the File associated with the current source file. 72 * @return The File. 73 */ 74 public File getSourceCodeFile() { 75 return sourceCodeFile; 76 } 77 78 /** 79 * Set the File associated with the current source file. 80 * While this may be set to <code>null</code>, the exclude/include 81 * facilities will not work properly without a File. 82 * @param sourceCodeFile The File. 83 */ 84 public void setSourceCodeFile(File sourceCodeFile) { 85 this.sourceCodeFile = sourceCodeFile; 86 } 87 88 /** 89 * Get the file name associated with the current source file. 90 * @return The file name. 91 */ 92 public String getSourceCodeFilename() { 93 return sourceCodeFilename; 94 } 95 96 /** 97 * Set the file name associated with the current source file. 98 * @param filename The file name. 99 */ 100 public void setSourceCodeFilename(String filename) { 101 this.sourceCodeFilename = filename; 102 } 103 104 /** 105 * Get the LanguageVersion associated with the current source file. 106 * @return The LanguageVersion, <code>null</code> if unknown. 107 */ 108 public LanguageVersion getLanguageVersion() { 109 return this.languageVersion; 110 } 111 112 /** 113 * Set the LanguageVersion associated with the current source file. 114 * This may be set to <code>null</code> to indicate the version is 115 * unknown and should be automatically determined. 116 * 117 * @param languageVersion The LanguageVersion. 118 */ 119 public void setLanguageVersion(LanguageVersion languageVersion) { 120 this.languageVersion = languageVersion; 121 } 122 123 /** 124 * Set an attribute value on the RuleContext, if it does not already exist. 125 * <p> 126 * Attributes can be shared between RuleContext instances. This operation 127 * is thread-safe. 128 * <p> 129 * Attribute values should be modified directly via the reference provided. 130 * It is not necessary to call <code>setAttribute(String, Object)</code> to 131 * update an attribute value. Modifications made to the attribute value 132 * will automatically be seen by other threads. Because of this, you must 133 * ensure the attribute values are themselves thread safe. 134 * 135 * @param name The attribute name. 136 * @param value The attribute value. 137 * @exception IllegalArgumentException if <code>name</code> or <code> value</code> are <code>null</code> 138 * @return <code>true</code> if the attribute was set, <code>false</code> otherwise. 139 */ 140 public boolean setAttribute(String name, Object value) { 141 if (name == null) { 142 throw new IllegalArgumentException("Parameter 'name' cannot be null."); 143 } 144 if (value == null) { 145 throw new IllegalArgumentException("Parameter 'value' cannot be null."); 146 } 147 synchronized (this.attributes) { 148 if (!this.attributes.containsKey(name)) { 149 this.attributes.put(name, value); 150 return true; 151 } else { 152 return false; 153 } 154 } 155 } 156 157 /** 158 * Get an attribute value on the RuleContext. 159 * <p> 160 * Attributes can be shared between RuleContext instances. This operation 161 * is thread-safe. 162 * <p> 163 * Attribute values should be modified directly via the reference provided. 164 * It is not necessary to call <code>setAttribute(String, Object)</code> to 165 * update an attribute value. Modifications made to the attribute value 166 * will automatically be seen by other threads. Because of this, you must 167 * ensure the attribute values are themselves thread safe. 168 * 169 * @param name The attribute name. 170 * @return The current attribute value, or <code>null</code> if the attribute does not exist. 171 */ 172 public Object getAttribute(String name) { 173 return this.attributes.get(name); 174 } 175 176 /** 177 * Remove an attribute value on the RuleContext. 178 * <p> 179 * Attributes can be shared between RuleContext instances. This operation 180 * is thread-safe. 181 * <p> 182 * Attribute values should be modified directly via the reference provided. 183 * It is not necessary to call <code>setAttribute(String, Object)</code> to 184 * update an attribute value. Modifications made to the attribute value 185 * will automatically be seen by other threads. Because of this, you must 186 * ensure the attribute values are themselves thread safe. 187 * 188 * @param name The attribute name. 189 * @return The current attribute value, or <code>null</code> if the attribute does not exist. 190 */ 191 public Object removeAttribute(String name) { 192 return this.attributes.remove(name); 193 } 194 195 /** 196 * Configure whether exceptions during applying a rule should be ignored or not. 197 * If set to <code>true</code> then such exceptions are logged as warnings and 198 * the processing is continued with the next rule - the failing rule is simply skipped. 199 * This is the default behavior. 200 * <br> 201 * If set to <code>false</code> then the processing will be aborted with the exception. 202 * This is especially useful during unit tests, in order to not oversee any exceptions. 203 * @param ignoreExceptions if <code>true</code> simply skip failing rules (default). 204 */ 205 public void setIgnoreExceptions(boolean ignoreExceptions) { 206 this.ignoreExceptions = ignoreExceptions; 207 } 208 209 /** 210 * Gets the configuration whether to skip failing rules (<code>true</code>) 211 * or whether to throw a a RuntimeException and abort the processing for the first 212 * failing rule. 213 * @return <code>true</code> when failing rules are skipped, <code>false</code> otherwise. 214 */ 215 public boolean isIgnoreExceptions() { 216 return ignoreExceptions; 217 } 218 }