| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| PkgControl |
|
| 3.0;3 |
| 1 | //////////////////////////////////////////////////////////////////////////////// | |
| 2 | // checkstyle: Checks Java source code for adherence to a set of rules. | |
| 3 | // Copyright (C) 2001-2014 Oliver Burn | |
| 4 | // | |
| 5 | // This library is free software; you can redistribute it and/or | |
| 6 | // modify it under the terms of the GNU Lesser General Public | |
| 7 | // License as published by the Free Software Foundation; either | |
| 8 | // version 2.1 of the License, or (at your option) any later version. | |
| 9 | // | |
| 10 | // This library is distributed in the hope that it will be useful, | |
| 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 | // Lesser General Public License for more details. | |
| 14 | // | |
| 15 | // You should have received a copy of the GNU Lesser General Public | |
| 16 | // License along with this library; if not, write to the Free Software | |
| 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 18 | //////////////////////////////////////////////////////////////////////////////// | |
| 19 | package com.puppycrawl.tools.checkstyle.checks.imports; | |
| 20 | ||
| 21 | import com.google.common.collect.Lists; | |
| 22 | import java.util.LinkedList; | |
| 23 | import java.util.List; | |
| 24 | ||
| 25 | /** | |
| 26 | * Represents the a tree of guards for controlling whether packages are allowed | |
| 27 | * to be used. Each instance must have a single parent or be the root node. | |
| 28 | * Each instance may have zero or more children. | |
| 29 | * | |
| 30 | * @author Oliver Burn | |
| 31 | */ | |
| 32 | 1 | class PkgControl |
| 33 | { | |
| 34 | /** List of {@link Guard} objects to check. */ | |
| 35 | 27 | private final LinkedList<Guard> mGuards = Lists.newLinkedList(); |
| 36 | /** List of children {@link PkgControl} objects. */ | |
| 37 | 27 | private final List<PkgControl> mChildren = Lists.newArrayList(); |
| 38 | /** The parent. Null indicates we are the root node. */ | |
| 39 | private final PkgControl mParent; | |
| 40 | /** The full package name for the node. */ | |
| 41 | private final String mFullPackage; | |
| 42 | ||
| 43 | /** | |
| 44 | * Construct a root node. | |
| 45 | * @param aPkgName the name of the package. | |
| 46 | */ | |
| 47 | PkgControl(final String aPkgName) | |
| 48 | 14 | { |
| 49 | 14 | assert aPkgName != null; |
| 50 | 14 | mParent = null; |
| 51 | 14 | mFullPackage = aPkgName; |
| 52 | 14 | } |
| 53 | ||
| 54 | /** | |
| 55 | * Construct a child node. | |
| 56 | * @param aParent the parent node. | |
| 57 | * @param aSubPkg the sub package name. | |
| 58 | */ | |
| 59 | PkgControl(final PkgControl aParent, final String aSubPkg) | |
| 60 | 13 | { |
| 61 | 13 | assert aParent != null; |
| 62 | 13 | assert aSubPkg != null; |
| 63 | 13 | mParent = aParent; |
| 64 | 13 | mFullPackage = aParent.getFullPackage() + "." + aSubPkg; |
| 65 | 13 | mParent.mChildren.add(this); |
| 66 | 13 | } |
| 67 | ||
| 68 | /** | |
| 69 | * Adds a guard to the node. | |
| 70 | * @param aThug the guard to be added. | |
| 71 | */ | |
| 72 | void addGuard(final Guard aThug) | |
| 73 | { | |
| 74 | 57 | mGuards.addFirst(aThug); |
| 75 | 57 | } |
| 76 | ||
| 77 | /** | |
| 78 | * @return the full package name represented by the node. | |
| 79 | */ | |
| 80 | String getFullPackage() | |
| 81 | { | |
| 82 | 38 | return mFullPackage; |
| 83 | } | |
| 84 | ||
| 85 | /** | |
| 86 | * Search down the tree to locate the finest match for a supplied package. | |
| 87 | * @param aForPkg the package to search for. | |
| 88 | * @return the finest match, or null if no match at all. | |
| 89 | */ | |
| 90 | PkgControl locateFinest(final String aForPkg) | |
| 91 | { | |
| 92 | // Check if we are a match. | |
| 93 | // This algormithm should be improved to check for a trailing "." | |
| 94 | // or nothing following. | |
| 95 | 21 | if (!aForPkg.startsWith(getFullPackage())) { |
| 96 | 7 | return null; |
| 97 | } | |
| 98 | ||
| 99 | // Check if any of the children match. | |
| 100 | 14 | for (PkgControl pc : mChildren) { |
| 101 | 8 | final PkgControl match = pc.locateFinest(aForPkg); |
| 102 | 8 | if (match != null) { |
| 103 | 6 | return match; |
| 104 | } | |
| 105 | 2 | } |
| 106 | ||
| 107 | // No match so I am the best there is. | |
| 108 | 8 | return this; |
| 109 | } | |
| 110 | ||
| 111 | /** | |
| 112 | * Returns whether a package is allowed to be used. The algorithm checks | |
| 113 | * with the current node for a result, and if none is found then calls | |
| 114 | * its parent looking for a match. This will recurse looking for match. | |
| 115 | * If there is no clear result then {@link AccessResult#UNKNOWN} is | |
| 116 | * returned. | |
| 117 | * @param aForImport the package to check on. | |
| 118 | * @param aInPkg the package doing the import. | |
| 119 | * @return an {@link AccessResult}. | |
| 120 | */ | |
| 121 | AccessResult checkAccess(final String aForImport, final String aInPkg) | |
| 122 | { | |
| 123 | 56 | final AccessResult retVal = localCheckAccess(aForImport, aInPkg); |
| 124 | 56 | if (retVal != AccessResult.UNKNOWN) { |
| 125 | 22 | return retVal; |
| 126 | } | |
| 127 | 34 | else if (mParent == null) { |
| 128 | // we are the top, so default to not allowed. | |
| 129 | 11 | return AccessResult.DISALLOWED; |
| 130 | } | |
| 131 | ||
| 132 | 23 | return mParent.checkAccess(aForImport, aInPkg); |
| 133 | } | |
| 134 | ||
| 135 | /** | |
| 136 | * Checks whether any of the guards for this node control access to | |
| 137 | * a specified package. | |
| 138 | * @param aForImport the package to check. | |
| 139 | * @param aInPkg the package doing the import. | |
| 140 | * @return an {@link AccessResult}. | |
| 141 | */ | |
| 142 | private AccessResult localCheckAccess(final String aForImport, | |
| 143 | final String aInPkg) | |
| 144 | { | |
| 145 | 56 | for (Guard g : mGuards) { |
| 146 | // Check if a Guard is only meant to be applied locally. | |
| 147 | 104 | if (g.isLocalOnly() && !mFullPackage.equals(aInPkg)) { |
| 148 | 10 | continue; |
| 149 | } | |
| 150 | 94 | final AccessResult result = g.verifyImport(aForImport); |
| 151 | 94 | if (result != AccessResult.UNKNOWN) { |
| 152 | 22 | return result; |
| 153 | } | |
| 154 | 72 | } |
| 155 | 34 | return AccessResult.UNKNOWN; |
| 156 | } | |
| 157 | } |