001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.types.selectors;
020:
021: import java.io.File;
022: import java.util.StringTokenizer;
023:
024: import org.apache.tools.ant.BuildException;
025: import org.apache.tools.ant.types.Parameter;
026:
027: /**
028: * Selector that filters files based on the how deep in the directory
029: * tree they are.
030: *
031: * @since 1.5
032: */
033: public class DepthSelector extends BaseExtendSelector {
034:
035: // CheckStyle:VisibilityModifier OFF - bc
036:
037: /** min attribute */
038: public int min = -1;
039: /** max attribute */
040: public int max = -1;
041:
042: // CheckStyle:VisibilityModifier ON
043:
044: /** Used for parameterized custom selector */
045: public static final String MIN_KEY = "min";
046: /** Used for parameterized custom selector */
047: public static final String MAX_KEY = "max";
048:
049: /**
050: * Creates a new <code>DepthSelector</code> instance.
051: *
052: */
053: public DepthSelector() {
054: }
055:
056: /**
057: * @return a string describing this object
058: */
059: public String toString() {
060: StringBuffer buf = new StringBuffer("{depthselector min: ");
061: buf.append(min);
062: buf.append(" max: ");
063: buf.append(max);
064: buf.append("}");
065: return buf.toString();
066: }
067:
068: /**
069: * The minimum depth below the basedir before a file is selected.
070: *
071: * @param min minimum directory levels below basedir to go
072: */
073: public void setMin(int min) {
074: this .min = min;
075: }
076:
077: /**
078: * The minimum depth below the basedir before a file is selected.
079: *
080: * @param max maximum directory levels below basedir to go
081: */
082: public void setMax(int max) {
083: this .max = max;
084: }
085:
086: /**
087: * When using this as a custom selector, this method will be called.
088: * It translates each parameter into the appropriate setXXX() call.
089: *
090: * @param parameters the complete set of parameters for this selector
091: */
092: public void setParameters(Parameter[] parameters) {
093: super .setParameters(parameters);
094: if (parameters != null) {
095: for (int i = 0; i < parameters.length; i++) {
096: String paramname = parameters[i].getName();
097: if (MIN_KEY.equalsIgnoreCase(paramname)) {
098: try {
099: setMin(Integer.parseInt(parameters[i]
100: .getValue()));
101: } catch (NumberFormatException nfe1) {
102: setError("Invalid minimum value "
103: + parameters[i].getValue());
104: }
105: } else if (MAX_KEY.equalsIgnoreCase(paramname)) {
106: try {
107: setMax(Integer.parseInt(parameters[i]
108: .getValue()));
109: } catch (NumberFormatException nfe1) {
110: setError("Invalid maximum value "
111: + parameters[i].getValue());
112: }
113: } else {
114: setError("Invalid parameter " + paramname);
115: }
116: }
117: }
118: }
119:
120: /**
121: * Checks to make sure all settings are kosher. In this case, it
122: * means that the max depth is not lower than the min depth.
123: */
124: public void verifySettings() {
125: if (min < 0 && max < 0) {
126: setError("You must set at least one of the min or the "
127: + "max levels.");
128: }
129: if (max < min && max > -1) {
130: setError("The maximum depth is lower than the minimum.");
131: }
132: }
133:
134: /**
135: * The heart of the matter. This is where the selector gets to decide
136: * on the inclusion of a file in a particular fileset. Most of the work
137: * for this selector is offloaded into SelectorUtils, a static class
138: * that provides the same services for both FilenameSelector and
139: * DirectoryScanner.
140: *
141: * @param basedir the base directory the scan is being done from
142: * @param filename is the name of the file to check
143: * @param file is a java.io.File object the selector can use
144: * @return whether the file should be selected or not
145: */
146: public boolean isSelected(File basedir, String filename, File file) {
147:
148: // throw BuildException on error
149: validate();
150:
151: int depth = -1;
152: // If you felt daring, you could cache the basedir absolute path
153: String absBase = basedir.getAbsolutePath();
154: String absFile = file.getAbsolutePath();
155: StringTokenizer tokBase = new StringTokenizer(absBase,
156: File.separator);
157: StringTokenizer tokFile = new StringTokenizer(absFile,
158: File.separator);
159: while (tokFile.hasMoreTokens()) {
160: String filetoken = tokFile.nextToken();
161: if (tokBase.hasMoreTokens()) {
162: String basetoken = tokBase.nextToken();
163: // Sanity check. Ditch it if you want faster performance
164: if (!basetoken.equals(filetoken)) {
165: throw new BuildException("File " + filename
166: + " does not appear within " + absBase
167: + "directory");
168: }
169: } else {
170: depth += 1;
171: if (max > -1 && depth > max) {
172: return false;
173: }
174: }
175: }
176: if (tokBase.hasMoreTokens()) {
177: throw new BuildException("File " + filename
178: + " is outside of " + absBase + "directory tree");
179: }
180: if (min > -1 && depth < min) {
181: return false;
182: }
183: return true;
184: }
185:
186: }
|