/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd; import java.io.File; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import net.sourceforge.pmd.lang.LanguageVersion; /** * The RuleContext provides access to Rule processing state. This information * includes the following global information: * <ul> * <li>The Report to which Rule Violations are sent.</li> * <li>Named attributes.</li> * </ul> * As well as the following source file specific information: * <ul> * <li>A File for the source file.</li> * <li>A String for the name of the source file.</li> * <li>The Language Version of the source file.</li> * </ul> * It is <strong>required</strong> that all source file specific options be set * between calls to difference source files. Failure to do so, may result in * undefined behavior. */ public class RuleContext { private Report report = new Report(); private File sourceCodeFile; private String sourceCodeFilename; private LanguageVersion languageVersion; private final ConcurrentMap<String, Object> attributes; private boolean ignoreExceptions = true; /** * Default constructor. */ public RuleContext() { attributes = new ConcurrentHashMap<>(); } /** * Constructor which shares attributes and report listeners with the given * RuleContext. * * @param ruleContext * the context from which the values are shared */ public RuleContext(RuleContext ruleContext) { this.attributes = ruleContext.attributes; this.report.addListeners(ruleContext.getReport().getListeners()); } /** * Get the Report to which Rule Violations are sent. * * @return The Report. */ public Report getReport() { return report; } /** * Set the Report to which Rule Violations are sent. * * @param report * The Report. */ public void setReport(Report report) { this.report = report; } /** * Get the File associated with the current source file. * * @return The File. */ public File getSourceCodeFile() { return sourceCodeFile; } /** * Set the File associated with the current source file. While this may be * set to <code>null</code>, the exclude/include facilities will not work * properly without a File. * * @param sourceCodeFile * The File. */ public void setSourceCodeFile(File sourceCodeFile) { this.sourceCodeFile = sourceCodeFile; } /** * Get the file name associated with the current source file. * * @return The file name. */ public String getSourceCodeFilename() { return sourceCodeFilename; } /** * Set the file name associated with the current source file. * * @param filename * The file name. */ public void setSourceCodeFilename(String filename) { this.sourceCodeFilename = filename; } /** * Get the LanguageVersion associated with the current source file. * * @return The LanguageVersion, <code>null</code> if unknown. */ public LanguageVersion getLanguageVersion() { return this.languageVersion; } /** * Set the LanguageVersion associated with the current source file. This may * be set to <code>null</code> to indicate the version is unknown and should * be automatically determined. * * @param languageVersion * The LanguageVersion. */ public void setLanguageVersion(LanguageVersion languageVersion) { this.languageVersion = languageVersion; } /** * Set an attribute value on the RuleContext, if it does not already exist. * <p> * Attributes can be shared between RuleContext instances. This operation is * thread-safe. * <p> * Attribute values should be modified directly via the reference provided. * It is not necessary to call <code>setAttribute(String, Object)</code> to * update an attribute value. Modifications made to the attribute value will * automatically be seen by other threads. Because of this, you must ensure * the attribute values are themselves thread safe. * * @param name * The attribute name. * @param value * The attribute value. * @exception IllegalArgumentException * if <code>name</code> or <code> value</code> are * <code>null</code> * @return <code>true</code> if the attribute was set, <code>false</code> * otherwise. */ public boolean setAttribute(String name, Object value) { if (name == null) { throw new IllegalArgumentException("Parameter 'name' cannot be null."); } if (value == null) { throw new IllegalArgumentException("Parameter 'value' cannot be null."); } return this.attributes.putIfAbsent(name, value) == null; } /** * Get an attribute value on the RuleContext. * <p> * Attributes can be shared between RuleContext instances. This operation is * thread-safe. * <p> * Attribute values should be modified directly via the reference provided. * It is not necessary to call <code>setAttribute(String, Object)</code> to * update an attribute value. Modifications made to the attribute value will * automatically be seen by other threads. Because of this, you must ensure * the attribute values are themselves thread safe. * * @param name * The attribute name. * @return The current attribute value, or <code>null</code> if the * attribute does not exist. */ public Object getAttribute(String name) { return this.attributes.get(name); } /** * Remove an attribute value on the RuleContext. * <p> * Attributes can be shared between RuleContext instances. This operation is * thread-safe. * <p> * Attribute values should be modified directly via the reference provided. * It is not necessary to call <code>setAttribute(String, Object)</code> to * update an attribute value. Modifications made to the attribute value will * automatically be seen by other threads. Because of this, you must ensure * the attribute values are themselves thread safe. * * @param name * The attribute name. * @return The current attribute value, or <code>null</code> if the * attribute does not exist. */ public Object removeAttribute(String name) { return this.attributes.remove(name); } /** * Configure whether exceptions during applying a rule should be ignored or * not. If set to <code>true</code> then such exceptions are logged as * warnings and the processing is continued with the next rule - the failing * rule is simply skipped. This is the default behavior. <br> * If set to <code>false</code> then the processing will be aborted with the * exception. This is especially useful during unit tests, in order to not * oversee any exceptions. * * @param ignoreExceptions * if <code>true</code> simply skip failing rules (default). */ public void setIgnoreExceptions(boolean ignoreExceptions) { this.ignoreExceptions = ignoreExceptions; } /** * Gets the configuration whether to skip failing rules (<code>true</code>) * or whether to throw a a RuntimeException and abort the processing for the * first failing rule. * * @return <code>true</code> when failing rules are skipped, * <code>false</code> otherwise. */ public boolean isIgnoreExceptions() { return ignoreExceptions; } }