From 6ffc8dd26075456b055ffcd35d3915c23049bfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20K=C3=BChne?= Date: Sat, 30 Nov 2002 18:29:44 +0000 Subject: [PATCH] avalonization --- .../tools/checkstyle/CheckStyleTask.java | 14 +- .../puppycrawl/tools/checkstyle/Checker.java | 128 +++++++------- .../tools/checkstyle/ConfigurationLoader.java | 158 +++++------------- .../com/puppycrawl/tools/checkstyle/Defn.java | 28 ---- .../com/puppycrawl/tools/checkstyle/Main.java | 35 +--- .../tools/checkstyle/PropertyCacheFile.java | 14 +- .../tools/checkstyle/TreeWalker.java | 151 ++++++++++++----- .../tools/checkstyle/api/Check.java | 35 +++- .../tools/checkstyle/api/FileSetCheck.java | 2 +- .../checks/AbstractFileSetCheck.java | 4 +- .../checkstyle/checks/TranslationCheck.java | 2 +- 11 files changed, 282 insertions(+), 289 deletions(-) diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java index ced196559..ea7b46249 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java @@ -40,6 +40,8 @@ import java.util.List; import java.util.Properties; import java.util.Iterator; +import com.puppycrawl.tools.checkstyle.api.Configuration; + /** * An implementation of a ANT task for calling checkstyle. See the documentation * of the task for usage. @@ -319,9 +321,15 @@ public class CheckStyleTask final Configuration config = ConfigurationLoader.loadConfiguration( mConfigFile.getAbsolutePath(), props); - config.setClassLoader(new AntClassLoader(getProject(), - mClasspath)); - c = new Checker(config); + + DefaultContext context = new DefaultContext(); + ClassLoader loader = new AntClassLoader(getProject(), mClasspath); + context.add("classloader", loader); + + c = new Checker(); + c.contextualize(context); + c.configure(config); + // setup the listeners AuditListener[] listeners = getListeners(); for (int i = 0; i < listeners.length; i++) { diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java index 5a2209ebc..e5cf2e116 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java @@ -18,22 +18,25 @@ //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle; -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; -import com.puppycrawl.tools.checkstyle.api.FileSetCheck; -import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; -import com.puppycrawl.tools.checkstyle.api.MessageDispatcher; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.Locale; +import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.api.FileSetCheck; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.api.MessageDispatcher; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; + /** * This class provides the functionality to check a set of files. * @author Oliver Burn * @author Stephane Bailliez * @author lkuehne */ -public class Checker +public class Checker extends AutomaticBean implements Defn, MessageDispatcher { /** @@ -89,73 +92,81 @@ public class Checker /** maintains error count */ private final ErrorCounter mCounter = new ErrorCounter(); - /** configuration */ - private final GlobalProperties mConfig; - /** vector of listeners */ private final ArrayList mListeners = new ArrayList(); /** vector of fileset checks */ private final ArrayList mFileSetChecks = new ArrayList(); - /** - * Creates a new Checker instance. - * - * @param aConfig the configuration to use - * @throws CheckstyleException if an error occurs - */ - public Checker(Configuration aConfig) - throws CheckstyleException + /** class loader to resolve classes with. **/ + private ClassLoader mLoader = + Thread.currentThread().getContextClassLoader(); + + /** the basedir to strip off in filenames */ + private String mBasedir; + + public void setLocaleCountry(String aLocaleCountry) { - this(aConfig.getGlobalProperties(), aConfig.getCheckConfigurations()); + mLocaleCountry = aLocaleCountry; } + public void setLocaleLanguage(String aLocaleLanguage) + { + mLocaleLanguage = aLocaleLanguage; + } + + /** locale country to report messages **/ + private String mLocaleCountry = Locale.getDefault().getCountry(); + /** locale language to report messages **/ + private String mLocaleLanguage = Locale.getDefault().getLanguage(); + /** * Creates a new Checker instance. + * The instance needs to be contextualized and configured. * - * @param aConfig the configuration to use - * @param aConfigs the configuation of the checks to use * @throws CheckstyleException if an error occurs */ - public Checker(GlobalProperties aConfig, CheckConfiguration[] aConfigs) + public Checker() throws CheckstyleException { - mConfig = aConfig; - LocalizedMessage.setLocale(new Locale(mConfig.getLocaleLanguage(), - mConfig.getLocaleCountry())); - - // TODO: create, configure and register the FileSetChecks from config - // file instead of hardcoding it here in the Checker constructor. - // Probably the addFileSetCheck mthod must be called from outside - // the checker, just like the TreeWalker is not concerned with - // finding all the checks it has to execute (IOC principle). - - // TODO: uncommenting the addFileSetCheck calls breaks the tests - // because the packageHtml check is always executed and yields - // additional errors that are not expected in the current test code - // (which should stay like it currently is!) - - //FileSetCheck translationCheck = new TranslationCheck(); - // addFileSetCheck(translationCheck); - - //FileSetCheck packageHtmlCheck = new PackageHtmlCheck(); - // addFileSetCheck(packageHtmlCheck); - - final TreeWalker walker = new TreeWalker(mConfig); - // TODO: improve the error handing - for (int i = 0; i < aConfigs.length; i++) { - final CheckConfiguration config = aConfigs[i]; - // IMPORTANT! Need to use the same class loader that created this - // class. Otherwise can get ClassCastException problems. - walker.registerCheck( - config.createInstance(this.getClass().getClassLoader()), - config); - } - addFileSetCheck(walker); - this.addListener(mCounter); } + /** @see AutomaticBean */ + public void configure(Configuration aConfiguration) + throws CheckstyleException + { + super.configure(aConfiguration); + + final Locale locale = new Locale(mLocaleLanguage, mLocaleCountry); + LocalizedMessage.setLocale(locale); + + DefaultContext context = new DefaultContext(); + context.add("classLoader", this.getClassLoader()); + Configuration[] fileSetChecks = aConfiguration.getChildren(); + for (int i = 0; i < fileSetChecks.length; i++) { + Configuration fscConf = fileSetChecks[i]; + String className = fscConf.getAttribute("classname"); + try { + Class clazz = Class.forName(className); + FileSetCheck fsc = (FileSetCheck) clazz.newInstance(); + fsc.contextualize(context); + fsc.configure(fscConf); + addFileSetCheck(fsc); + } + catch (Exception ex) { + // TODO i18n + throw new CheckstyleException( + "cannot initialize filesetcheck of class " + className); + } + } + } + + private ClassLoader getClassLoader() + { + return mLoader; + } + /** * Adds a FileSetCheck to the list of FileSetChecks * that is executed in process(). @@ -211,18 +222,21 @@ public class Checker private String getStrippedFileName(final String aFileName) { final String stripped; - final String basedir = mConfig.getBasedir(); - if ((basedir == null) || !aFileName.startsWith(basedir)) { + if ((mBasedir == null) || !aFileName.startsWith(mBasedir)) { stripped = aFileName; } else { // making the assumption that there is text after basedir - final int skipSep = basedir.endsWith(File.separator) ? 0 : 1; - stripped = aFileName.substring(basedir.length() + skipSep); + final int skipSep = mBasedir.endsWith(File.separator) ? 0 : 1; + stripped = aFileName.substring(mBasedir.length() + skipSep); } return stripped; } + public void setBasedir(String aBasedir) + { + mBasedir = aBasedir; + } /** notify all listeners about the audit start */ protected void fireAuditStarted() diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/ConfigurationLoader.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/ConfigurationLoader.java index 62e6cc106..26f60b150 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/ConfigurationLoader.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/ConfigurationLoader.java @@ -21,14 +21,12 @@ package com.puppycrawl.tools.checkstyle; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; import java.util.Properties; - +import java.util.Stack; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; -import org.apache.regexp.RESyntaxException; +import com.puppycrawl.tools.checkstyle.api.Configuration; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -51,20 +49,10 @@ class ConfigurationLoader private Properties mOverrideProps = new Properties(); /** parser to read XML files **/ private final XMLReader mParser; - /** the loaded global properties **/ - private final Properties mProps = new Properties(); - /** the loaded configurations **/ - private final ArrayList mCheckConfigs = new ArrayList(); /** the loaded configuration **/ - private Configuration mConfig = null; - /** the current check configuration being created **/ - private CheckConfiguration mCurrent; - /** buffer for collecting text **/ - private final StringBuffer mBuf = new StringBuffer(); - /** in global element **/ - private boolean mIsInGlobalElement = false; - /** started processing check configurations **/ - private boolean mIsInCheckMode = false; + private Stack mConfigStack = new Stack(); + /** the Configuration that is beeing built */ + private Configuration mConfiguration = null; /** * Creates a new ConfigurationLoader instance. @@ -91,71 +79,50 @@ class ConfigurationLoader mParser.parse(new InputSource(new FileReader(aFilename))); } - /** - * Returns the configuration information in the last file parsed. - * @return list of CheckConfiguration objects - */ - CheckConfiguration[] getConfigs() - { - return (CheckConfiguration[]) mCheckConfigs.toArray( - new CheckConfiguration[mCheckConfigs.size()]); - } - - /////////////////////////////////////////////////////////////////////////// // Document handler methods /////////////////////////////////////////////////////////////////////////// - /** @see org.xml.sax.helpers.DefaultHandler **/ - public void characters(char[] aChars, int aStart, int aLength) - { - mBuf.append(String.valueOf(aChars, aStart, aLength)); - } - /** @see org.xml.sax.helpers.DefaultHandler **/ public void startElement(String aNamespaceURI, String aLocalName, String aQName, Attributes aAtts) + throws SAXException { - mBuf.setLength(0); - if ("global".equals(aQName)) { - mIsInGlobalElement = true; - } - else if ("check".equals(aQName)) { - //first apply overriding properties - if (!mIsInCheckMode) { - mIsInCheckMode = true; - for (Enumeration enum = mOverrideProps.keys(); - enum.hasMoreElements();) - { - final String key = (String) enum.nextElement(); - final String value = (String) mOverrideProps.get(key); - mProps.setProperty(key, value); + // TODO: debug logging for support puposes + DefaultConfiguration conf = new DefaultConfiguration(aQName); + System.out.println("aQName = " + aQName); + final int attCount = aAtts.getLength(); + for (int i = 0; i < attCount; i++) { + String name = aAtts.getQName(i); + String value = aAtts.getValue(i); + System.out.println(" value of " + name + " is " + value); + + // expand properties + if (value.startsWith("${") && value.endsWith("}")) { + String propName = value.substring(2, value.length() - 1); + value = mOverrideProps.getProperty(propName); + if (value == null) { + throw new SAXException("missing external property " + propName); } + System.out.println(" propName = " + propName); + System.out.println(" new value = " + value); } - mCurrent = new CheckConfiguration(); - mCurrent.setClassname(aAtts.getValue("classname")); - } - else if ("property".equals(aQName)) { - final String name = aAtts.getValue("name"); - String value = aAtts.getValue("value"); - - if (value == null) { - //try global - String globalKey = aAtts.getValue("from-global"); - value = (String) mProps.get(globalKey); - } - - if (mIsInGlobalElement) { - mProps.setProperty(name, value); - } - else { - mCurrent.addProperty(name, value); - } + conf.addAttribute(name, value); } + if (mConfiguration == null) { + mConfiguration = conf; + } + + if (!mConfigStack.isEmpty()) { + DefaultConfiguration top = (DefaultConfiguration) mConfigStack.peek(); + top.addChild(conf); + } + + mConfigStack.push(conf); } /** @see org.xml.sax.helpers.DefaultHandler **/ @@ -163,44 +130,7 @@ class ConfigurationLoader String aLocalName, String aQName) { - if ("global".equals(aQName)) { - mIsInGlobalElement = false; - } - else if ("check".equals(aQName)) { - mCheckConfigs.add(mCurrent); - mCurrent = null; - } - else if ("tokens".equals(aQName)) { - mCurrent.addTokens(mBuf.toString()); - } - } - - /** - * Returns the check configurations in a specified file. - * @param aConfigFname name of config file - * @return the check configurations - * @throws CheckstyleException if an error occurs - */ - public static CheckConfiguration[] loadConfigs(String aConfigFname) - throws CheckstyleException - { - try { - final ConfigurationLoader loader = new ConfigurationLoader(); - loader.parseFile(aConfigFname); - return loader.getConfigs(); - } - catch (FileNotFoundException e) { - throw new CheckstyleException("unable to find " + aConfigFname); - } - catch (ParserConfigurationException e) { - throw new CheckstyleException("unable to parse " + aConfigFname); - } - catch (SAXException e) { - throw new CheckstyleException("unable to parse " + aConfigFname); - } - catch (IOException e) { - throw new CheckstyleException("unable to read " + aConfigFname); - } + mConfigStack.pop(); } /** @@ -227,32 +157,20 @@ class ConfigurationLoader throw new CheckstyleException("unable to parse " + aConfigFname); } catch (SAXException e) { - throw new CheckstyleException("unable to parse " + aConfigFname); + throw new CheckstyleException("unable to parse " + + aConfigFname + " - " + e.getMessage()); } catch (IOException e) { throw new CheckstyleException("unable to read " + aConfigFname); } - catch (RESyntaxException e) { - throw new CheckstyleException( - "A regular expression error exists in " + aConfigFname); - } } /** * Returns the configuration in the last file parsed. * @return Configuration object - * @throws RESyntaxException if an error occurs - * @throws FileNotFoundException if an error occurs - * @throws IOException if an error occurs */ private Configuration getConfiguration() - throws IOException, FileNotFoundException, RESyntaxException { - final GlobalProperties globalProps = - new GlobalProperties(mProps, System.out); - final CheckConfiguration[] checkConfigs = - (CheckConfiguration[]) mCheckConfigs.toArray( - new CheckConfiguration[mCheckConfigs.size()]); - return new Configuration(globalProps, checkConfigs); + return mConfiguration; } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java index 6615c8831..be58e8d06 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java @@ -28,32 +28,4 @@ public interface Defn // TODO: Change to a class - follow the advice of Bloch. /** name of resource bundle for Checkstyle */ String CHECKSTYLE_BUNDLE = "com.puppycrawl.tools.checkstyle.messages"; - - /** property name for allowing protected data **/ - String TAB_WIDTH_PROP = "checkstyle.tab.width"; - /** property name for cache file **/ - String CACHE_FILE_PROP = "checkstyle.cache.file"; - - /** property name for the base directory **/ - String BASEDIR_PROP = "checkstyle.basedir"; - - /** property name for the locale language for reporting **/ - String LOCALE_LANGUAGE_PROP = "checkstyle.locale.language"; - /** property name for the locale country for reporting **/ - String LOCALE_COUNTRY_PROP = "checkstyle.locale.country"; - - /** All the integer properties */ - String[] ALL_INT_PROPS = new String[] - { - TAB_WIDTH_PROP, - }; - - /** All the String properties */ - String[] ALL_STRING_PROPS = new String[] - { - BASEDIR_PROP, - CACHE_FILE_PROP, - LOCALE_COUNTRY_PROP, - LOCALE_LANGUAGE_PROP, - }; } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Main.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Main.java index a4199964e..94d19164e 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Main.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Main.java @@ -34,6 +34,7 @@ import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; +import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; @@ -86,24 +87,11 @@ public final class Main usage(); } - // Load the config file -// CheckConfiguration[] checkConfigs = null; -// try { -// checkConfigs = -// ConfigurationLoader.loadConfigs(line.getOptionValue("c")); -// } -// catch (CheckstyleException e) { -// System.out.println("Error loading configuration file"); -// e.printStackTrace(System.out); -// System.exit(1); -// } - // Load the config file Configuration config = null; try { - config = - ConfigurationLoader.loadConfiguration(line.getOptionValue("c"), - props); + config = ConfigurationLoader.loadConfiguration( + line.getOptionValue("c"), props); } catch (CheckstyleException e) { System.out.println("Error loading configuration file"); @@ -166,24 +154,11 @@ public final class Main usage(); } -// // create the checker -// Checker c = null; -// try { -// c = new Checker(new GlobalProperties(props, System.out), -// checkConfigs); -// c.addListener(listener); -// } -// catch (Exception e) { -// System.out.println("Unable to create Checker: " -// + e.getMessage()); -// e.printStackTrace(System.out); -// System.exit(1); -// } - // create the checker Checker c = null; try { - c = new Checker(config); + c = new Checker(); + c.configure(config); c.addListener(listener); } catch (Exception e) { diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/PropertyCacheFile.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/PropertyCacheFile.java index 1690790b6..54bd245a7 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/PropertyCacheFile.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/PropertyCacheFile.java @@ -24,13 +24,16 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; import java.util.Properties; import java.security.MessageDigest; +import com.puppycrawl.tools.checkstyle.api.Configuration; + /** * This class maintains a persistent store of the files that have * checked ok and their associated timestamp. It uses a property file - * for storage. A hashcode of the GlobalProperties is stored in the + * for storage. A hashcode of the Configuration is stored in the * cache file to ensure the cache is invalidated when the * configuration has changed. * @@ -56,10 +59,10 @@ class PropertyCacheFile * * @param aCurrentConfig the current configuration, not null */ - PropertyCacheFile(GlobalProperties aCurrentConfig) + PropertyCacheFile(Configuration aCurrentConfig, String aFileName) { boolean setInActive = true; - final String fileName = aCurrentConfig.getCacheFile(); + final String fileName = aFileName; if (fileName != null) { try { mDetails.load(new FileInputStream(fileName)); @@ -79,6 +82,7 @@ class PropertyCacheFile setInActive = false; } catch (IOException e) { + // TODO: use logger System.out.println("Unable to open cache file, ignoring."); e.printStackTrace(System.out); } @@ -128,10 +132,10 @@ class PropertyCacheFile * @param aConfiguration the GlobalProperties * @return the hashcode for aConfiguration */ - private String getConfigHashCode(GlobalProperties aConfiguration) + private String getConfigHashCode(Serializable aConfiguration) { try { - // im-memory serialization of GlobalProperties + // im-memory serialization of Configuration ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java index 8662925d1..7c3d3892b 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java @@ -18,29 +18,30 @@ //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle; -import com.puppycrawl.tools.checkstyle.api.Check; -import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.LocalizedMessages; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.api.FileContents; -import com.puppycrawl.tools.checkstyle.api.Utils; -import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; -import com.puppycrawl.tools.checkstyle.checks.AbstractFileSetCheck; - +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Reader; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; -import java.util.Arrays; -import java.io.Reader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; import antlr.RecognitionException; import antlr.TokenStreamException; +import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FileContents; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessages; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.api.Utils; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.checks.AbstractFileSetCheck; /** * Responsible for walking an abstract syntax tree and notifying interested @@ -105,27 +106,72 @@ public final class TreeWalker private final Set mAllChecks = new HashSet(); /** collects the error messages */ private final LocalizedMessages mMessages; - /** the tab width for error reporting */ - private final int mTabWidth; + /** the distance between tab stops */ + private int mTabWidth = 8; /** cache file **/ - private final PropertyCacheFile mCache; + private PropertyCacheFile mCache = new PropertyCacheFile(null, null); + /** * the global configuration. * TODO: should only know the treewalker part of the config */ - private final GlobalProperties mConfig; + private Configuration mConfig; + + private ClassLoader mClassLoader; /** * Creates a new TreeWalker instance. - * - * @param aConfig the configuration to use */ - public TreeWalker(GlobalProperties aConfig) + public TreeWalker() { mMessages = new LocalizedMessages(); - mConfig = aConfig; - mTabWidth = aConfig.getTabWidth(); - mCache = new PropertyCacheFile(aConfig); + } + + /** sets the distance between tab stops */ + public void setTabWidth(int aTabWidth) + { + mTabWidth = aTabWidth; + } + + public void setCacheFile(String aFileName) + { + mCache = new PropertyCacheFile(mConfig, aFileName); + } + + // TODO: Call from contextualize + public void setClassLoader(ClassLoader aClassLoader) + { + mClassLoader = aClassLoader; + } + + public void configure(Configuration aConfiguration) + throws CheckstyleException + { + super.configure(aConfiguration); + mConfig = aConfiguration; + + DefaultContext checkContext = new DefaultContext(); + checkContext.add("classLoader", mClassLoader); + checkContext.add("messages", mMessages); + // TODO: hmmm.. this looks less than elegant + checkContext.add("tabWidth", String.valueOf(mTabWidth)); + + // TODO: improve the error handing + Configuration[] checkConfigs = aConfiguration.getChildren(); + for (int i = 0; i < checkConfigs.length; i++) { + final Configuration config = checkConfigs[i]; + // IMPORTANT! Need to use the same class loader that created this + // class. Otherwise can get ClassCastException problems. + final String className = config.getAttribute("classname"); + final Check check = createCheck( + this.getClass().getClassLoader(), className); + + check.contextualize(checkContext); + check.configure(config); + + registerCheck(check); + } + } /** @@ -147,7 +193,7 @@ public final class TreeWalker final String[] lines = Utils.getLines(fileName); final FileContents contents = new FileContents(fileName, lines); final DetailAST rootAST = TreeWalker.parse(contents); - walk(rootAST, contents, mConfig.getClassLoader()); + walk(rootAST, contents); } catch (FileNotFoundException fnfe) { mMessages.add(new LocalizedMessage(0, Defn.CHECKSTYLE_BUNDLE, @@ -184,16 +230,15 @@ public final class TreeWalker /** * Register a check for a given configuration. * @param aCheck the check to register - * @param aConfig the configuration to use */ - void registerCheck(Check aCheck, CheckConfiguration aConfig) + void registerCheck(Check aCheck) + throws CheckstyleException { - aCheck.setMessages(mMessages); - aCheck.setTabWidth(mTabWidth); - if (!aConfig.getTokens().isEmpty()) { + final Set checkTokens = aCheck.getTokens(); + if (!checkTokens.isEmpty()) { int acceptableTokens[] = aCheck.getAcceptableTokens(); Arrays.sort(acceptableTokens); - final Iterator it = aConfig.getTokens().iterator(); + final Iterator it = checkTokens.iterator(); while (it.hasNext()) { String token = (String) it.next(); int tokenId = TokenTypes.getTokenId(token); @@ -242,12 +287,11 @@ public final class TreeWalker * Initiates the walk of an AST. * @param aAST the root AST * @param aContents the contents of the file the AST was generated from - * @param aLoader the class loader for resolving classes */ - void walk(DetailAST aAST, FileContents aContents, ClassLoader aLoader) + private void walk(DetailAST aAST, FileContents aContents) { mMessages.reset(); - notifyBegin(aContents, aLoader); + notifyBegin(aContents); // empty files are not flagged by javac, will yield aAST == null if (aAST != null) { @@ -261,9 +305,8 @@ public final class TreeWalker /** * Notify interested checks that about to begin walking a tree. * @param aContents the contents of the file the AST was generated from - * @param aLoader the class loader for resolving classes */ - private void notifyBegin(FileContents aContents, ClassLoader aLoader) + private void notifyBegin(FileContents aContents) { // TODO: do not track Context properly for token final Iterator it = mAllChecks.iterator(); @@ -272,7 +315,6 @@ public final class TreeWalker final HashMap treeContext = new HashMap(); check.setTreeContext(treeContext); check.setFileContents(aContents); - check.setClassLoader(aLoader); check.beginTree(); } } @@ -355,7 +397,7 @@ public final class TreeWalker } /** - * + * Static helper method to parses a Java source file. * @param aContents contains the contents of the file * @return the root of the AST * @throws TokenStreamException if lexing failed @@ -418,4 +460,37 @@ public final class TreeWalker super.destroy(); mCache.destroy(); } + + /** + * Create an instance of the check that is properly initialised. + * + * @param aLoader the ClassLoader to create the instance with + * @return the created check + * @throws CheckstyleException if an error occurs + */ + private Check createCheck( + ClassLoader aLoader, String aClassName) + throws CheckstyleException + { + try { + final Class clazz = Class.forName(aClassName, true, aLoader); + final Check check = (Check) clazz.newInstance(); + return check; + } + catch (ClassNotFoundException e) { + throw new CheckstyleException( + "Unable to find class for " + aClassName); + } + catch (InstantiationException e) { + throw new CheckstyleException( + "Unable to instantiate " + aClassName); + } + catch (IllegalAccessException e) { + throw new CheckstyleException( + "Unable to instantiate " + aClassName); + } + } + + + } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java index 2e4203155..855dcdc01 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java @@ -18,7 +18,9 @@ //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle.api; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** * The base class for checks. @@ -26,18 +28,18 @@ import java.util.Map; * @author Oliver Burn * @version 1.0 */ -public abstract class Check +public abstract class Check extends AutomaticBean { /** resuable constant for message formating */ private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; /** name to store file contents under */ private static final String FILE_CONTENTS_ATTRIBUTE = "fILEcONTENTS"; - /** name to store class loader under */ - private static final String CLASS_LOADER_ATTRIBUTE = "cLaSsLoAdEr"; /** the global context for the check */ private Map mGlobalContext; + /** the tokens the check is interested in */ + private final Set mTokens = new HashSet(); /** * the object for collecting messages. decided to not put in the global * context for performance and ease of use. @@ -50,6 +52,8 @@ public abstract class Check /** the tab with for column reporting */ private int mTabWidth = 8; // meaningful default + private ClassLoader mLoader = Thread.currentThread().getContextClassLoader(); + /** * Returns the default token a check is interested in. Only used if the * configuration for a check does not define the tokens. @@ -84,6 +88,27 @@ public abstract class Check // // Lets worry about it when it becomes a problem. + /** + * Adds a set of tokens the check is interested in. + * @param aStrRep the string representation of the tokens interested in + */ + final public void setTokens(String[] aStrRep) + { + for (int i = 0; i < aStrRep.length; i++) { + String s = aStrRep[i]; + mTokens.add(s); + } + } + + /** + * Returns the tokens registered for the check. + * @return the set of token names + */ + final public Set getTokens() + { + return mTokens; + } + /** * Return the global context object for check. This context is valid for @@ -231,7 +256,7 @@ public abstract class Check */ public final void setClassLoader(ClassLoader aLoader) { - getTreeContext().put(CLASS_LOADER_ATTRIBUTE, aLoader); + mLoader = aLoader; } /** @@ -240,7 +265,7 @@ public abstract class Check */ public final ClassLoader getClassLoader() { - return (ClassLoader) getTreeContext().get(CLASS_LOADER_ATTRIBUTE); + return mLoader; } /** @return the tab width to report errors with */ diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileSetCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileSetCheck.java index 0cc55a370..8436f574e 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileSetCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/FileSetCheck.java @@ -25,7 +25,7 @@ import java.io.File; * * @author lkuehne */ -public interface FileSetCheck +public interface FileSetCheck extends Configurable, Contextualizable { /** * Sets the MessageDispatcher that is used to dispatch error diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractFileSetCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractFileSetCheck.java index 9405947f7..d13a04896 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractFileSetCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractFileSetCheck.java @@ -24,6 +24,7 @@ import java.io.File; import com.puppycrawl.tools.checkstyle.api.FileSetCheck; import com.puppycrawl.tools.checkstyle.api.MessageDispatcher; +import com.puppycrawl.tools.checkstyle.api.AutomaticBean; /** * Provides common functionality for many FileSetChecks. @@ -34,7 +35,8 @@ import com.puppycrawl.tools.checkstyle.api.MessageDispatcher; * * @author lkuehne */ -public abstract class AbstractFileSetCheck implements FileSetCheck +public abstract class AbstractFileSetCheck + extends AutomaticBean implements FileSetCheck { /** The dispatcher errors are fired to. */ private MessageDispatcher mDispatcher = null; diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java index c22826221..b1e5a241f 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java @@ -210,7 +210,7 @@ public class TranslationCheck extends AbstractFileSetCheck for (Iterator it = keysClone.iterator(); it.hasNext();) { Object[] key = new Object[]{it.next()}; LocalizedMessage[] errors = new LocalizedMessage[1]; - final String bundle = getClass().getName() + ".messages"; + final String bundle = getClass().getPackage().getName() + ".messages"; errors[0] = new LocalizedMessage( 0, bundle, "translation.missingKey", key); getMessageDispatcher().fireErrors(path, errors);