001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2007 Oliver Burn
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: package com.puppycrawl.tools.checkstyle.checks.imports;
020:
021: import java.io.File;
022: import java.net.URI;
023:
024: import com.puppycrawl.tools.checkstyle.api.Check;
025: import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
026: import com.puppycrawl.tools.checkstyle.api.DetailAST;
027: import com.puppycrawl.tools.checkstyle.api.FullIdent;
028: import com.puppycrawl.tools.checkstyle.api.TokenTypes;
029: import org.apache.commons.beanutils.ConversionException;
030:
031: /**
032: * Check that controls what packages can be imported in each package. Useful
033: * for ensuring that application layering is not violated. Ideas on how the
034: * check can be improved include support for:
035: * <ul>
036: * <li>Change the default policy that if a package being checked does not
037: * match any guards, then it is allowed. Currently defaults to disallowed.
038: *
039: * </ul>
040: * @author Oliver Burn
041: */
042: public class ImportControlCheck extends Check {
043: /** The root package controller. */
044: private PkgControl mRoot;
045: /** The package doing the import. */
046: private String mInPkg;
047:
048: /**
049: * The package controller for the current file. Used for performance
050: * optimisation.
051: */
052: private PkgControl mCurrentLeaf;
053:
054: /** {@inheritDoc} */
055: public int[] getDefaultTokens() {
056: return new int[] { TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT,
057: TokenTypes.STATIC_IMPORT, };
058: }
059:
060: /** {@inheritDoc} */
061: public void beginTree(final DetailAST aRootAST) {
062: mCurrentLeaf = null;
063: }
064:
065: /** {@inheritDoc} */
066: public void visitToken(final DetailAST aAST) {
067: if (aAST.getType() == TokenTypes.PACKAGE_DEF) {
068: final DetailAST nameAST = aAST.getLastChild()
069: .getPreviousSibling();
070: final FullIdent full = FullIdent.createFullIdent(nameAST);
071: if (mRoot == null) {
072: log(nameAST, "import.control.missing.file");
073: } else {
074: mInPkg = full.getText();
075: mCurrentLeaf = mRoot.locateFinest(mInPkg);
076: if (mCurrentLeaf == null) {
077: log(nameAST, "import.control.unknown.pkg");
078: }
079: }
080: } else if (mCurrentLeaf != null) {
081: final FullIdent imp;
082: if (aAST.getType() == TokenTypes.IMPORT) {
083: imp = FullIdent.createFullIdentBelow(aAST);
084: } else {
085: // know it is a static import
086: imp = FullIdent.createFullIdent((DetailAST) aAST
087: .getFirstChild().getNextSibling());
088: }
089: final AccessResult access = mCurrentLeaf.checkAccess(imp
090: .getText(), mInPkg);
091: if (!AccessResult.ALLOWED.equals(access)) {
092: log(aAST, "import.control.disallowed", imp.getText());
093: }
094: }
095: }
096:
097: /**
098: * Set the parameter for the url containing the import control
099: * configuration. It will cause the url to be loaded.
100: * @param aUrl the url of the file to load.
101: * @throws ConversionException on error loading the file.
102: */
103: public void setUrl(final String aUrl) {
104: // Handle empty param
105: if ((aUrl == null) || (aUrl.trim().length() == 0)) {
106: return;
107: }
108: final URI uri;
109: try {
110: uri = URI.create(aUrl);
111: } catch (final IllegalArgumentException ex) {
112: throw new ConversionException(
113: "syntax error in url " + aUrl, ex);
114: }
115: try {
116: mRoot = ImportControlLoader.load(uri);
117: } catch (final CheckstyleException ex) {
118: throw new ConversionException("Unable to load " + aUrl, ex);
119: }
120: }
121:
122: /**
123: * Set the parameter for the file containing the import control
124: * configuration. It will cause the file to be loaded.
125: * @param aName the name of the file to load.
126: * @throws ConversionException on error loading the file.
127: */
128: public void setFile(final String aName) {
129: // Handle empty param
130: if ((aName == null) || (aName.trim().length() == 0)) {
131: return;
132: }
133:
134: try {
135: mRoot = ImportControlLoader.load(new File(aName).toURI());
136: } catch (final CheckstyleException ex) {
137: throw new ConversionException("Unable to load " + aName, ex);
138: }
139: }
140: }
|