diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java index ea7f80742..265467e25 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java @@ -30,6 +30,7 @@ import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; import com.puppycrawl.tools.checkstyle.api.MessageDispatcher; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.PackageNamesBean; +import com.puppycrawl.tools.checkstyle.api.Context; /** * This class provides the functionality to check a set of files. @@ -117,6 +118,9 @@ public class Checker extends AutomaticBean */ private String[] mPackageNames; + /** the context of all child components */ + private Context mChildContext; + /** * Creates a new Checker instance. * The instance needs to be contextualized and configured. @@ -130,37 +134,42 @@ public class Checker extends AutomaticBean } /** @see AutomaticBean */ - public void configure(Configuration aConfig) + public void finishLocalSetup() throws CheckstyleException { - super.configure(aConfig); - final Locale locale = new Locale(mLocaleLanguage, mLocaleCountry); LocalizedMessage.setLocale(locale); final DefaultContext context = new DefaultContext(); context.add("classLoader", mLoader); - final Configuration[] fileSetChecks = aConfig.getChildren(); - for (int i = 0; i < fileSetChecks.length; i++) { - final Configuration fscConf = fileSetChecks[i]; - final String name = fscConf.getName(); - try { - final FileSetCheck fsc = + mChildContext = context; + } + + /** + * Instantiates, configures and registers a FileSetCheck + * that is specified in the provided configuration. + * @see com.puppycrawl.tools.checkstyle.api.AutomaticBean + */ + protected void setupChild(Configuration aChildConf) + throws CheckstyleException + { + final String name = aChildConf.getName(); + try { + final FileSetCheck fsc = (FileSetCheck) PackageObjectFactory.makeObject( - getPackageNames(), - getClass().getClassLoader(), - name); - fsc.setPackageNames(getPackageNames()); - fsc.contextualize(context); - fsc.configure(fscConf); - addFileSetCheck(fsc); - } - catch (Exception ex) { - // TODO i18n - throw new CheckstyleException( - "cannot initialize filesetcheck with name " - + name + " - " + ex.getMessage()); - } + getPackageNames(), + getClass().getClassLoader(), + name); + fsc.setPackageNames(getPackageNames()); + fsc.contextualize(mChildContext); + fsc.configure(aChildConf); + addFileSetCheck(fsc); + } + catch (Exception ex) { + // TODO i18n + throw new CheckstyleException( + "cannot initialize filesetcheck with name " + + name + " - " + ex.getMessage()); } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java index 96a4fe446..1aa5e87a0 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/TreeWalker.java @@ -42,6 +42,7 @@ 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.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.Context; /** * Responsible for walking an abstract syntax tree and notifying interested @@ -111,15 +112,12 @@ public final class TreeWalker /** cache file **/ private PropertyCacheFile mCache = new PropertyCacheFile(null, null); - /** - * the global configuration. - * TODO: should only know the treewalker part of the config - */ - private Configuration mConfig; - /** class loader to resolve classes with. **/ private ClassLoader mClassLoader; + /** context of child components */ + private Context mChildContext; + /** * Creates a new TreeWalker instance. */ @@ -137,7 +135,8 @@ public final class TreeWalker /** @param aFileName the cache file */ public void setCacheFile(String aFileName) { - mCache = new PropertyCacheFile(mConfig, aFileName); + final Configuration configuration = getConfiguration(); + mCache = new PropertyCacheFile(configuration, aFileName); } // TODO: Call from contextualize @@ -148,35 +147,39 @@ public final class TreeWalker } /** @see com.puppycrawl.tools.checkstyle.api.Configurable */ - public void configure(Configuration aConfiguration) - throws CheckstyleException + public void finishLocalSetup() { - 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)); + mChildContext = checkContext; + } + + /** + * Instantiates, configures and registers a Check that is specified + * in the provided configuration. + * @see com.puppycrawl.tools.checkstyle.api.AutomaticBean + */ + public void setupChild(Configuration aChildConf) + throws CheckstyleException + { // 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 name = config.getName(); - final String[] packageNames = getPackageNames(); - final Check check = - (Check) PackageObjectFactory.makeObject( + + // IMPORTANT! Need to use the same class loader that created this + // class. Otherwise can get ClassCastException problems. + final String name = aChildConf.getName(); + final String[] packageNames = getPackageNames(); + final Check check = + (Check) PackageObjectFactory.makeObject( packageNames, this.getClass().getClassLoader(), name); - check.contextualize(checkContext); - check.configure(config); + check.contextualize(mChildContext); + check.configure(aChildConf); - registerCheck(check); - } + registerCheck(check); } /** diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/AutomaticBean.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/AutomaticBean.java index 832ad7bc2..fc56959e1 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/AutomaticBean.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/AutomaticBean.java @@ -64,6 +64,12 @@ public class AutomaticBean implements Configurable, Contextualizable private static void initConverters() { // TODO: is there a smarter way to tell beanutils not to use defaults? + + // If any runtime environment like ANT or an IDE would use beanutils + // with different converters we would really be stuck here. + // Having to configure a static utility class in this way is really + // strange, it seems like a design problem in BeanUtils + boolean[] booleanArray = new boolean[0]; byte[] byteArray = new byte[0]; char[] charArray = new char[0]; @@ -114,13 +120,27 @@ public class AutomaticBean implements Configurable, Contextualizable // do not use defaults in the default configuration of ConvertUtils } + /** the configuration of this bean */ + private Configuration mConfiguration; + /** * Implements the Configurable interface using bean introspection. + * + * Subclasses are allowed to add behaviour. After the bean + * based setup has completed first the method + * {@link #finishLocalSetup finishLocalSetup} + * is called to allow completion of the bean's local setup, + * after that the method {@link #setupChild setupChild} + * is called for each {@link Configuration#getChildren child Configuration} + * of aConfiguration. + * * @see Configurable */ - public void configure(Configuration aConfiguration) + public final void configure(Configuration aConfiguration) throws CheckstyleException { + mConfiguration = aConfiguration; + // TODO: debug log messages final String[] attributes = aConfiguration.getAttributeNames(); @@ -142,13 +162,22 @@ public class AutomaticBean implements Configurable, Contextualizable + this.getClass().getName()); } } + + finishLocalSetup(); + + Configuration[] childConfigs = aConfiguration.getChildren(); + for (int i = 0; i < childConfigs.length; i++) { + Configuration childConfig = childConfigs[i]; + setupChild(childConfig); + } } /** * Implements the Contextualizable interface using bean introspection. * @see Contextualizable */ - public void contextualize(Context aContext) throws CheckstyleException + public final void contextualize(Context aContext) + throws CheckstyleException { // TODO: debug log messages final String[] attributes = aContext.getAttributeNames(); @@ -174,6 +203,41 @@ public class AutomaticBean implements Configurable, Contextualizable } } } + + /** + * Returns the configuration that was used to configure this component. + * @return the configuration that was used to configure this component. + */ + protected final Configuration getConfiguration() + { + return mConfiguration; + } + + /** + * Provides a hook to finish the part of this compoent's setup that + * was not handled by the bean introspection. + *

+ * The default implementation does nothing. + *

+ * @throws CheckstyleException if there is a configuration error. + */ + protected void finishLocalSetup() throws CheckstyleException + { + } + + /** + * Called by configure() for every child of this component's Configuration. + *

+ * The default implementation does nothing. + *

+ * @param aChildConf a child of this component's Configuration + * @throws CheckstyleException if there is a configuration error. + * @see Configuration#getChildren + */ + protected void setupChild(Configuration aChildConf) + throws CheckstyleException + { + } } /**