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