View Javadoc
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<>();
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 }