001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2019 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.checks.imports;
021
022import java.net.URI;
023import java.util.Collections;
024import java.util.Set;
025import java.util.regex.Pattern;
026
027import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
028import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
029import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
030import com.puppycrawl.tools.checkstyle.api.DetailAST;
031import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
032import com.puppycrawl.tools.checkstyle.api.FullIdent;
033import com.puppycrawl.tools.checkstyle.api.TokenTypes;
034
035/**
036 * <p>
037 * Controls what can be imported in each package and file. Useful for ensuring
038 * that application layering rules are not violated, especially on large projects.
039 * </p>
040 * <p>
041 * You can control imports based on the a package name or based on the file name.
042 * When controlling packages, all files and sub-packages in the declared package
043 * will be controlled by this check. To specify differences between a main package
044 * and a sub-package, you must define the sub-package inside the main package.
045 * When controlling file, only the file name is considered and only files processed by
046 * <a href="https://checkstyle.org/config.html#TreeWalker">TreeWalker</a>.
047 * The file's extension is ignored.
048 * </p>
049 * <p>
050 * Short description of the behaviour:
051 * </p>
052 * <ul>
053 * <li>
054 * Check starts checking from the longest matching subpackage (later 'current subpackage') or
055 * the first file name match described inside import control file to package defined in class file.
056 * <ul>
057 * <li>
058 * The longest matching subpackage is found by starting with the root package and
059 * examining if the any of the sub-packages or file definitions match the current
060 * class' package or file name.
061 * </li>
062 * <li>
063 * If a file name is matched first, that is considered the longest match and becomes
064 * the current file/subpackage.
065 * </li>
066 * <li>
067 * If another subpackage is matched, then it's subpackages and file names are examined
068 * for the next longest match and the process repeats recursively.
069 * </li>
070 * <li>
071 * If no subpackages or file names are matched, the current subpackage is then used.
072 * </li>
073 * </ul>
074 * </li>
075 * <li>
076 * Order of rules in the same subpackage/root are defined by the order of declaration
077 * in the XML file, which is from top (first) to bottom (last).
078 * </li>
079 * <li>
080 * If there is matching allow/disallow rule inside the current file/subpackage
081 * then the Check returns the first "allowed" or "disallowed" message.
082 * </li>
083 * <li>
084 * If there is no matching allow/disallow rule inside the current file/subpackage
085 * then it continues checking in the parent subpackage.
086 * </li>
087 * <li>
088 * If there is no matching allow/disallow rule in any of the files/subpackages,
089 * including the root level (import-control), then the import is disallowed by default.
090 * </li>
091 * </ul>
092 * <p>
093 * The DTD for a import control XML document is at
094 * <a href="https://checkstyle.org/dtds/import_control_1_4.dtd">
095 * https://checkstyle.org/dtds/import_control_1_4.dtd</a>.
096 * It contains documentation on each of the elements and attributes.
097 * </p>
098 * <p>
099 * The check validates a XML document when it loads the document. To validate against
100 * the above DTD, include the following document type declaration in your XML document:
101 * </p>
102 * <pre>
103 * &lt;!DOCTYPE import-control PUBLIC
104 *     "-//Checkstyle//DTD ImportControl Configuration 1.4//EN"
105 *     "https://checkstyle.org/dtds/import_control_1_4.dtd"&gt;
106 * </pre>
107 * <ul>
108 * <li>
109 * Property {@code file} - Specify the location of the file containing the
110 * import control configuration. It can be a regular file, URL or resource path.
111 * It will try loading the path as a URL first, then as a file, and finally as a resource.
112 * Default value is {@code null}.
113 * </li>
114 * <li>
115 * Property {@code path} - Specify the regular expression of file paths to which
116 * this check should apply. Files that don't match the pattern will not be checked.
117 * The pattern will be matched against the full absolute file path.
118 * Default value is {@code ".*"}.
119 * </li>
120 * </ul>
121 * <p>
122 * To configure the check using an import control file called "config/import-control.xml",
123 * then have the following:
124 * </p>
125 * <pre>
126 * &lt;module name="ImportControl"&gt;
127 *   &lt;property name="file" value="config/import-control.xml"/&gt;
128 * &lt;/module&gt;
129 * </pre>
130 * <p>
131 * To configure the check to only check the "src/main" directory using an import
132 * control file called "config/import-control.xml", then have the following:
133 * </p>
134 * <pre>
135 * &lt;module name="ImportControl"&gt;
136 *   &lt;property name="file" value="config/import-control.xml"/&gt;
137 *   &lt;property name="path" value="^.*[\\/]src[\\/]main[\\/].*$"/&gt;
138 * &lt;/module&gt;
139 * </pre>
140 * <p>
141 * In the example below access to package {@code com.puppycrawl.tools.checkstyle.checks}
142 * and its subpackages is allowed from anywhere in {@code com.puppycrawl.tools.checkstyle}
143 * except from the {@code filters} subpackage where access to all {@code check}'s
144 * subpackages is disallowed. Two {@code java.lang.ref} classes are allowed by virtue
145 * of one regular expression instead of listing them in two separate allow rules
146 * (as it is done with the {@code Files} and {@code ClassPath} classes).
147 * </p>
148 * <pre>
149 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle"&gt;
150 *   &lt;disallow pkg="sun"/&gt;
151 *   &lt;allow pkg="com.puppycrawl.tools.checkstyle.api"/&gt;
152 *   &lt;allow pkg="com.puppycrawl.tools.checkstyle.checks"/&gt;
153 *   &lt;allow class="com.google.common.io.Files"/&gt;
154 *   &lt;allow class="com.google.common.reflect.ClassPath"/&gt;
155 *   &lt;subpackage name="filters"&gt;
156 *     &lt;allow class="java\.lang\.ref\.(Weak|Soft)Reference"
157 *       regex="true"/&gt;
158 *     &lt;disallow pkg="com\.puppycrawl\.tools\.checkstyle\.checks\.[^.]+"
159 *       regex="true"/&gt;
160 *     &lt;disallow pkg="com.puppycrawl.tools.checkstyle.ant"/&gt;
161 *     &lt;disallow pkg="com.puppycrawl.tools.checkstyle.gui"/&gt;
162 *   &lt;/subpackage&gt;
163 *   &lt;subpackage name="dao"&gt;
164 *     &lt;disallow pkg="javax.swing" exact-match="true"/&gt;
165 *   &lt;/subpackage&gt;
166 * &lt;/import-control&gt;
167 * </pre>
168 * <p>
169 * In the next example regular expressions are used to enforce a layering rule:
170 * In all {@code dao} packages it is not allowed to access UI layer code ({@code ui},
171 * {@code awt}, and {@code swing}). On the other hand it is not allowed to directly
172 * access {@code dao} and {@code service} layer from {@code ui} packages.
173 * The root package is also a regular expression that is used to handle old and
174 * new domain name with the same rules.
175 * </p>
176 * <pre>
177 * &lt;import-control pkg="(de.olddomain|de.newdomain)\..*" regex="true"&gt;
178 *   &lt;subpackage pkg="[^.]+\.dao" regex="true"&gt;
179 *     &lt;disallow pkg=".*\.ui" regex="true"/&gt;
180 *     &lt;disallow pkg=".*\.(awt|swing).\.*" regex="true"/&gt;
181 *   &lt;/subpackage&gt;
182 *   &lt;subpackage pkg="[^.]+\.ui" regex="true"&gt;
183 *     &lt;disallow pkg=".*\.(dao|service)" regex="true"/&gt;
184 *   &lt;/subpackage&gt;
185 * &lt;/import-control&gt;
186 * </pre>
187 * <p>
188 * In the next examples usage of {@code strategyOnMismatch} property is shown.
189 * This property defines strategy in a case when no matching allow/disallow rule was found.
190 * Property {@code strategyOnMismatch} is attribute of {@code import-control} and
191 * {@code subpackage} tags. Property can have following values for {@code import-control} tag:
192 * </p>
193 * <ul>
194 * <li>
195 * disallowed (default value) - if there is no matching allow/disallow rule in any of
196 * the subpackages, including the root level (import-control), then the import is disallowed.
197 * </li>
198 * <li>
199 * allowed - if there is no matching allow/disallow rule in any of the subpackages,
200 * including the root level, then the import is allowed.
201 * </li>
202 * </ul>
203 * <p>
204 * And following values for {@code subpackage} tags:
205 * </p>
206 * <ul>
207 * <li>
208 * delegateToParent (default value) - if there is no matching allow/disallow rule
209 * inside the current subpackage, then it continues checking in the parent subpackage.
210 * </li>
211 * <li>
212 * allowed - if there is no matching allow/disallow rule inside the current subpackage,
213 * then the import is allowed.
214 * </li>
215 * <li>
216 * disallowed - if there is no matching allow/disallow rule inside the current subpackage,
217 * then the import is disallowed.
218 * </li>
219 * </ul>
220 * <p>
221 * The following example demonstrates usage of {@code strategyOnMismatch}
222 * property for {@code import-control} tag. Here all imports are allowed except
223 * {@code java.awt.Image} and {@code java.io.File} classes.
224 * </p>
225 * <pre>
226 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"
227 *   strategyOnMismatch="allowed"&gt;
228 *   &lt;disallow class="java.awt.Image"/&gt;
229 *   &lt;disallow class="java.io.File"/&gt;
230 * &lt;/import-control&gt;
231 * </pre>
232 * <p>
233 * In the example below, any import is disallowed inside
234 * {@code com.puppycrawl.tools.checkstyle.checks.imports} package except imports
235 * from package {@code javax.swing} and class {@code java.io.File}.
236 * However, any import is allowed in the classes outside of
237 * {@code com.puppycrawl.tools.checkstyle.checks.imports} package.
238 * </p>
239 * <pre>
240 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"
241 *   strategyOnMismatch="allowed"&gt;
242 *   &lt;subpackage name="imports" strategyOnMismatch="disallowed"&gt;
243 *     &lt;allow pkg="javax.swing"/&gt;
244 *     &lt;allow class="java.io.File"/&gt;
245 *   &lt;/subpackage&gt;
246 * &lt;/import-control&gt;
247 * </pre>
248 * <p>
249 * When {@code strategyOnMismatch} has {@code allowed} or {@code disallowed}
250 * value for {@code subpackage} tag, it makes {@code subpackage} isolated from
251 * parent rules. In the next example, if no matching rule was found inside
252 * {@code com.puppycrawl.tools.checkstyle.checks.filters} then it continues
253 * checking in the parent subpackage, while for
254 * {@code com.puppycrawl.tools.checkstyle.checks.imports} import will be allowed by default.
255 * </p>
256 * <pre>
257 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"&gt;
258 *   &lt;allow class="java\.awt\.Image" regex="true"/&gt;
259 *   &lt;allow class="java\..*\.File" local-only="true" regex="true"/&gt;
260 *   &lt;subpackage name="imports" strategyOnMismatch="allowed"&gt;
261 *     &lt;allow pkg="javax\.swing" regex="true"/&gt;
262 *     &lt;allow pkg="java\.io" exact-match="true"
263 *       local-only="true" regex="true"/&gt;
264 *   &lt;/subpackage&gt;
265 *   &lt;subpackage name="filters"&gt;
266 *     &lt;allow class="javax.util.Date"/&gt;
267 *   &lt;/subpackage&gt;
268 * &lt;/import-control&gt;
269 * </pre>
270 * <p>
271 * In the example below, only file names that end with "Panel", "View", or "Dialog"
272 * in the package {@code gui} are disallowed to have imports from {@code com.mycompany.dao}
273 * and any {@code jdbc} package. In addition, only the file name named "PresentationModel"
274 * in the package {@code gui} are disallowed to have imports that match {@code javax.swing.J*}.
275 * All other imports in the package are allowed.
276 * </p>
277 * <pre>
278 * &lt;import-control pkg="com.mycompany.billing"&gt;
279 *   &lt;subpackage name="gui" strategyOnMismatch="allowed"&gt;
280 *     &lt;file name=".*(Panel|View|Dialog)" regex="true"&gt;
281 *       &lt;disallow pkg="com.mycompany.dao"/&gt;
282 *       &lt;disallow pkg=".*\.jdbc" regex="true"/&gt;
283 *     &lt;/file&gt;
284 *     &lt;file name="PresentationModel"&gt;
285 *       &lt;disallow pkg="javax\.swing\.J.*" regex="true"/&gt;
286 *     &lt;/file&gt;
287 *   &lt;/subpackage&gt;
288 * &lt;/import-control&gt;
289 * </pre>
290 * <p>
291 * For a real-life import control file look at the file called
292 * <a href="https://github.com/checkstyle/checkstyle/blob/master/config/import-control.xml">
293 * import-control.xml</a> which is part of the Checkstyle distribution.
294 * </p>
295 * <p id="blacklist-example">Example of blacklist mode</p>
296 * <p>
297 * To have a <b>blacklist mode</b>, it is required to have disallows inside
298 * subpackage and to have allow rule inside parent of the current subpackage
299 * to catch classes and packages those are not in the blacklist.
300 * </p>
301 * <p>
302 * In the example below any import from {@code java.util}({@code java.util.List},
303 * {@code java.util.Date}) package is allowed except {@code java.util.Map}
304 * inside subpackage {@code com.puppycrawl.tools.checkstyle.filters}.
305 * </p>
306 * <pre>
307 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle"&gt;
308 *   &lt;allow pkg="java.util"/&gt;
309 *   &lt;subpackage name="filters" &gt;
310 *     &lt;disallow class="java.util.Map"/&gt;
311 *   &lt;/subpackage&gt;
312 * &lt;/import-control&gt;
313 * </pre>
314 * <p>
315 * In the next example imports {@code java.util.stream.Stream} and
316 * {@code java.util.stream.Collectors} are disallowed inside
317 * {@code com.puppycrawl.tools.checkstyle.checks.imports} package, but because of
318 * {@code &lt;allow pkg="java.util.stream"/&gt;} every import from
319 * {@code java.util.stream} is allowed except described ones.
320 * </p>
321 * <pre>
322 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"&gt;
323 *   &lt;allow pkg="java.util.stream"/&gt;
324 *   &lt;subpackage name="imports"&gt;
325 *     &lt;disallow class="java.util.stream.Stream"/&gt;
326 *     &lt;disallow class="java.util.stream.Collectors"/&gt;
327 *   &lt;/subpackage&gt;
328 * &lt;/import-control&gt;
329 * </pre>
330 * <pre>
331 * package com.puppycrawl.tools.checkstyle.checks.imports;
332 *
333 * import java.util.stream.Stream;     // violation here
334 * import java.util.stream.Collectors; // violation here
335 * import java.util.stream.IntStream;
336 * </pre>
337 * <p>
338 * In the following example, all imports are allowed except the classes
339 * {@code java.util.Date}, {@code java.util.List} and package {@code sun}.
340 * </p>
341 * <pre>
342 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"&gt;
343 *   &lt;allow pkg=".*" regex="true"/&gt;
344 *   &lt;subpackage name="imports"&gt;
345 *     &lt;disallow class="java.util.Date"/&gt;
346 *     &lt;disallow class="java.util.List"/&gt;
347 *     &lt;disallow pkg="sun"/&gt;
348 *   &lt;/subpackage&gt;
349 * &lt;/import-control&gt;
350 * </pre>
351 * <p>
352 * In the following example, all imports of the {@code java.util} package are
353 * allowed except the {@code java.util.Date} class.
354 * </p>
355 * <pre>
356 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"&gt;
357 *   &lt;disallow class="java.util.Date"/&gt;
358 *
359 *   &lt;allow pkg="java.util"/&gt;
360 * &lt;/import-control&gt;
361 * </pre>
362 * <p id="regex-notes">Notes on regular expressions</p>
363 * <p>
364 * Regular expressions in import rules have to match either Java packages or classes.
365 * The language rules for packages and class names can be described by the following
366 * complicated regular expression that takes into account that Java names may contain
367 * any unicode letter, numbers, underscores, and dollar signs (see section 3.8 in the
368 * <a href="https://docs.oracle.com/javase/specs/">Java specs</a>):
369 * </p>
370 * <ul>
371 * <li>
372 * {@code [\p{Letter}_$][\p{Letter}\p{Number}_$]*} or short {@code [\p{L}_$][\p{L}\p{N}_$]*}
373 * for a class name or package component.
374 * </li>
375 * <li>
376 * {@code ([\p{L}_$][\p{L}\p{N}_$]*\.)*[\p{L}_$][\p{L}\p{N}_$]*} for a fully qualified name.
377 * </li>
378 * </ul>
379 * <p>
380 * But it is not necessary to use these complicated expressions since no validation is required.
381 * Differentiating between package separator '.' and others is sufficient.
382 * Unfortunately '.' has a special meaning in regular expressions so one has to write {@code \.}
383 * to match an actual dot.
384 * </p>
385 * <ul>
386 * <li>
387 * Use {@code [^.]+}(one or more "not a dot" characters) for a class name or package component.
388 * </li>
389 * <li>
390 * Use {@code com\.google\.common\.[^.]+} to match any subpackage of {@code com.google.common}.
391 * </li>
392 * <li>
393 * When matching concrete packages like {@code com.google.common} omitting the backslash before
394 * the dots may improve readability and may be just exact enough: {@code com.google.common\.[^.]+}
395 * matches not only subpackages of {@code com.google.common} but e.g. also of
396 * {@code com.googleecommon} but you may not care for that.
397 * </li>
398 * <li>
399 * Do not use {@code .*} unless you really do not care for what is matched.
400 * Often you want to match only a certain package level instead.
401 * </li>
402 * </ul><p id="static-import-notes">Notes on static imports</p>
403 * <p>
404 * Static members (including methods, constants and static inner classes)
405 * have to be explicitly allowed when they are imported, they are not automatically
406 * allowed along with their enclosing class.
407 * </p>
408 * <p>
409 * For example, to allow importing both {@code java.util.Map} and {@code java.util.Map.Entry}
410 * use the following configuration:
411 * </p>
412 * <pre>
413 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle"&gt;
414 *   &lt;allow class="java.util.Map"/&gt;
415 *   &lt;allow class="java.util.Map.Entry"/&gt;
416 * &lt;/import-control&gt;
417 * </pre>
418 * <p>
419 * It is also possible to use a regex with a wildcard:
420 * </p>
421 * <pre>
422 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle"&gt;
423 *   &lt;allow class="java.util.Map"/&gt;
424 *   &lt;allow class="java.util.Map.*" regex="true" /&gt;
425 * &lt;/import-control&gt;
426 * </pre>
427 *
428 * @since 4.0
429 */
430@FileStatefulCheck
431public class ImportControlCheck extends AbstractCheck implements ExternalResourceHolder {
432
433    /**
434     * A key is pointing to the warning message text in "messages.properties"
435     * file.
436     */
437    public static final String MSG_MISSING_FILE = "import.control.missing.file";
438
439    /**
440     * A key is pointing to the warning message text in "messages.properties"
441     * file.
442     */
443    public static final String MSG_UNKNOWN_PKG = "import.control.unknown.pkg";
444
445    /**
446     * A key is pointing to the warning message text in "messages.properties"
447     * file.
448     */
449    public static final String MSG_DISALLOWED = "import.control.disallowed";
450
451    /**
452     * A part of message for exception.
453     */
454    private static final String UNABLE_TO_LOAD = "Unable to load ";
455
456    /**
457     * Specify the location of the file containing the import control configuration.
458     * It can be a regular file, URL or resource path. It will try loading the path
459     * as a URL first, then as a file, and finally as a resource.
460     */
461    private URI file;
462
463    /**
464     * Specify the regular expression of file paths to which this check should apply.
465     * Files that don't match the pattern will not be checked. The pattern will
466     * be matched against the full absolute file path.
467     */
468    private Pattern path = Pattern.compile(".*");
469    /** Whether to process the current file. */
470    private boolean processCurrentFile;
471
472    /** The root package controller. */
473    private PkgImportControl root;
474    /** The package doing the import. */
475    private String packageName;
476    /** The file name doing the import. */
477    private String fileName;
478
479    /**
480     * The package controller for the current file. Used for performance
481     * optimisation.
482     */
483    private AbstractImportControl currentImportControl;
484
485    @Override
486    public int[] getDefaultTokens() {
487        return getRequiredTokens();
488    }
489
490    @Override
491    public int[] getAcceptableTokens() {
492        return getRequiredTokens();
493    }
494
495    @Override
496    public int[] getRequiredTokens() {
497        return new int[] {TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT, };
498    }
499
500    @Override
501    public void beginTree(DetailAST rootAST) {
502        currentImportControl = null;
503        processCurrentFile = path.matcher(getFileContents().getFileName()).find();
504        fileName = getFileContents().getText().getFile().getName();
505
506        final int period = fileName.lastIndexOf('.');
507
508        if (period != -1) {
509            fileName = fileName.substring(0, period);
510        }
511    }
512
513    @Override
514    public void visitToken(DetailAST ast) {
515        if (processCurrentFile) {
516            if (ast.getType() == TokenTypes.PACKAGE_DEF) {
517                if (root == null) {
518                    log(ast, MSG_MISSING_FILE);
519                }
520                else {
521                    packageName = getPackageText(ast);
522                    currentImportControl = root.locateFinest(packageName, fileName);
523                    if (currentImportControl == null) {
524                        log(ast, MSG_UNKNOWN_PKG);
525                    }
526                }
527            }
528            else if (currentImportControl != null) {
529                final String importText = getImportText(ast);
530                final AccessResult access = currentImportControl.checkAccess(packageName, fileName,
531                        importText);
532                if (access != AccessResult.ALLOWED) {
533                    log(ast, MSG_DISALLOWED, importText);
534                }
535            }
536        }
537    }
538
539    @Override
540    public Set<String> getExternalResourceLocations() {
541        return Collections.singleton(file.toString());
542    }
543
544    /**
545     * Returns package text.
546     * @param ast PACKAGE_DEF ast node
547     * @return String that represents full package name
548     */
549    private static String getPackageText(DetailAST ast) {
550        final DetailAST nameAST = ast.getLastChild().getPreviousSibling();
551        return FullIdent.createFullIdent(nameAST).getText();
552    }
553
554    /**
555     * Returns import text.
556     * @param ast ast node that represents import
557     * @return String that represents importing class
558     */
559    private static String getImportText(DetailAST ast) {
560        final FullIdent imp;
561        if (ast.getType() == TokenTypes.IMPORT) {
562            imp = FullIdent.createFullIdentBelow(ast);
563        }
564        else {
565            // know it is a static import
566            imp = FullIdent.createFullIdent(ast
567                    .getFirstChild().getNextSibling());
568        }
569        return imp.getText();
570    }
571
572    /**
573     * Setter to specify the location of the file containing the import control configuration.
574     * It can be a regular file, URL or resource path. It will try loading the path
575     * as a URL first, then as a file, and finally as a resource.
576     *
577     * @param uri the uri of the file to load.
578     * @throws IllegalArgumentException on error loading the file.
579     */
580    public void setFile(URI uri) {
581        // Handle empty param
582        if (uri != null) {
583            try {
584                root = ImportControlLoader.load(uri);
585                file = uri;
586            }
587            catch (CheckstyleException ex) {
588                throw new IllegalArgumentException(UNABLE_TO_LOAD + uri, ex);
589            }
590        }
591    }
592
593    /**
594     * Setter to specify the regular expression of file paths to which this check should apply.
595     * Files that don't match the pattern will not be checked. The pattern will be matched
596     * against the full absolute file path.
597     *
598     * @param pattern the file path regex this check should apply to.
599     */
600    public void setPath(Pattern pattern) {
601        path = pattern;
602    }
603
604}