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.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.LinkedList;
024: import java.util.List;
025:
026: /**
027: * Represents the a tree of guards for controlling whether packages are allowed
028: * to be used. Each instance must have a single parent or be the root node.
029: * Each instance may have zero or more children.
030: *
031: * @author Oliver Burn
032: */
033: class PkgControl {
034: /** List of {@link Guard} objects to check. */
035: private final LinkedList mGuards = new LinkedList();
036: /** List of children {@link PkgControl} objects. */
037: private final List mChildren = new ArrayList();
038: /** The parent. Null indicates we are the root node. */
039: private final PkgControl mParent;
040: /** The full package name for the node. */
041: private final String mFullPackage;
042:
043: /**
044: * Construct a root node.
045: * @param aPkgName the name of the package.
046: */
047: PkgControl(final String aPkgName) {
048: assert aPkgName != null;
049: mParent = null;
050: mFullPackage = aPkgName;
051: }
052:
053: /**
054: * Construct a child node.
055: * @param aParent the parent node.
056: * @param aSubPkg the sub package name.
057: */
058: PkgControl(final PkgControl aParent, final String aSubPkg) {
059: assert aParent != null;
060: assert aSubPkg != null;
061: mParent = aParent;
062: mFullPackage = aParent.getFullPackage() + "." + aSubPkg;
063: mParent.mChildren.add(this );
064: }
065:
066: /**
067: * Adds a guard to the node.
068: * @param aThug the guard to be added.
069: */
070: void addGuard(final Guard aThug) {
071: mGuards.addFirst(aThug);
072: }
073:
074: /**
075: * @return the full package name represented by the node.
076: */
077: String getFullPackage() {
078: return mFullPackage;
079: }
080:
081: /**
082: * Search down the tree to locate the finest match for a supplied package.
083: * @param aForPkg the package to search for.
084: * @return the finest match, or null if no match at all.
085: */
086: PkgControl locateFinest(final String aForPkg) {
087: // Check if we are a match.
088: // This algormithm should be improved to check for a trailing "."
089: // or nothing following.
090: if (!aForPkg.startsWith(getFullPackage())) {
091: return null;
092: }
093:
094: // Check if any of the children match.
095: final Iterator it = mChildren.iterator();
096: while (it.hasNext()) {
097: final PkgControl pc = (PkgControl) it.next();
098: final PkgControl match = pc.locateFinest(aForPkg);
099: if (match != null) {
100: return match;
101: }
102: }
103:
104: // No match so I am the best there is.
105: return this ;
106: }
107:
108: /**
109: * Returns whether a package is allowed to be used. The algorithm checks
110: * with the current node for a result, and if none is found then calls
111: * its parent looking for a match. This will recurse looking for match.
112: * If there is no clear result then {@link AccessResult#UNKNOWN} is
113: * returned.
114: * @param aForImport the package to check on.
115: * @param aInPkg the package doing the import.
116: * @return an {@link AccessResult}.
117: */
118: AccessResult checkAccess(final String aForImport,
119: final String aInPkg) {
120: final AccessResult retVal = localCheckAccess(aForImport, aInPkg);
121: if (retVal != AccessResult.UNKNOWN) {
122: return retVal;
123: } else if (mParent == null) {
124: // we are the top, so default to not allowed.
125: return AccessResult.DISALLOWED;
126: }
127:
128: return mParent.checkAccess(aForImport, aInPkg);
129: }
130:
131: /**
132: * Checks whether any of the guards for this node control access to
133: * a specified package.
134: * @param aForImport the package to check.
135: * @param aInPkg the package doing the import.
136: * @return an {@link AccessResult}.
137: */
138: private AccessResult localCheckAccess(final String aForImport,
139: final String aInPkg) {
140: final Iterator it = mGuards.iterator();
141: while (it.hasNext()) {
142: final Guard g = (Guard) it.next();
143: // Check if a Guard is only meant to be applied locally.
144: if (g.isLocalOnly() && !mFullPackage.equals(aInPkg)) {
145: continue;
146: }
147: final AccessResult result = g.verifyImport(aForImport);
148: if (result != AccessResult.UNKNOWN) {
149: return result;
150: }
151: }
152: return AccessResult.UNKNOWN;
153: }
154: }
|