1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.types.selectors;
  18. import java.io.File;
  19. import java.util.StringTokenizer;
  20. import org.apache.tools.ant.BuildException;
  21. import org.apache.tools.ant.types.Parameter;
  22. /**
  23. * Selector that filters files based on the how deep in the directory
  24. * tree they are.
  25. *
  26. * @since 1.5
  27. */
  28. public class DepthSelector extends BaseExtendSelector {
  29. public int min = -1;
  30. public int max = -1;
  31. /** Used for parameterized custom selector */
  32. public static final String MIN_KEY = "min";
  33. /** Used for parameterized custom selector */
  34. public static final String MAX_KEY = "max";
  35. /**
  36. * Creates a new <code>DepthSelector</code> instance.
  37. *
  38. */
  39. public DepthSelector() {
  40. }
  41. /**
  42. * @return a string describing this object
  43. */
  44. public String toString() {
  45. StringBuffer buf = new StringBuffer("{depthselector min: ");
  46. buf.append(min);
  47. buf.append(" max: ");
  48. buf.append(max);
  49. buf.append("}");
  50. return buf.toString();
  51. }
  52. /**
  53. * The minimum depth below the basedir before a file is selected.
  54. *
  55. * @param min minimum directory levels below basedir to go
  56. */
  57. public void setMin(int min) {
  58. this.min = min;
  59. }
  60. /**
  61. * The minimum depth below the basedir before a file is selected.
  62. *
  63. * @param max maximum directory levels below basedir to go
  64. */
  65. public void setMax(int max) {
  66. this.max = max;
  67. }
  68. /**
  69. * When using this as a custom selector, this method will be called.
  70. * It translates each parameter into the appropriate setXXX() call.
  71. *
  72. * @param parameters the complete set of parameters for this selector
  73. */
  74. public void setParameters(Parameter[] parameters) {
  75. super.setParameters(parameters);
  76. if (parameters != null) {
  77. for (int i = 0; i < parameters.length; i++) {
  78. String paramname = parameters[i].getName();
  79. if (MIN_KEY.equalsIgnoreCase(paramname)) {
  80. try {
  81. setMin(Integer.parseInt(parameters[i].getValue()));
  82. } catch (NumberFormatException nfe1) {
  83. setError("Invalid minimum value "
  84. + parameters[i].getValue());
  85. }
  86. } else if (MAX_KEY.equalsIgnoreCase(paramname)) {
  87. try {
  88. setMax(Integer.parseInt(parameters[i].getValue()));
  89. } catch (NumberFormatException nfe1) {
  90. setError("Invalid maximum value "
  91. + parameters[i].getValue());
  92. }
  93. } else {
  94. setError("Invalid parameter " + paramname);
  95. }
  96. }
  97. }
  98. }
  99. /**
  100. * Checks to make sure all settings are kosher. In this case, it
  101. * means that the max depth is not lower than the min depth.
  102. */
  103. public void verifySettings() {
  104. if (min < 0 && max < 0) {
  105. setError("You must set at least one of the min or the "
  106. + "max levels.");
  107. }
  108. if (max < min && max > -1) {
  109. setError("The maximum depth is lower than the minimum.");
  110. }
  111. }
  112. /**
  113. * The heart of the matter. This is where the selector gets to decide
  114. * on the inclusion of a file in a particular fileset. Most of the work
  115. * for this selector is offloaded into SelectorUtils, a static class
  116. * that provides the same services for both FilenameSelector and
  117. * DirectoryScanner.
  118. *
  119. * @param basedir the base directory the scan is being done from
  120. * @param filename is the name of the file to check
  121. * @param file is a java.io.File object the selector can use
  122. * @return whether the file should be selected or not
  123. */
  124. public boolean isSelected(File basedir, String filename, File file) {
  125. // throw BuildException on error
  126. validate();
  127. int depth = -1;
  128. // If you felt daring, you could cache the basedir absolute path
  129. String absBase = basedir.getAbsolutePath();
  130. String absFile = file.getAbsolutePath();
  131. StringTokenizer tokBase = new StringTokenizer(absBase,
  132. File.separator);
  133. StringTokenizer tokFile = new StringTokenizer(absFile,
  134. File.separator);
  135. while (tokFile.hasMoreTokens()) {
  136. String filetoken = tokFile.nextToken();
  137. if (tokBase.hasMoreTokens()) {
  138. String basetoken = tokBase.nextToken();
  139. // Sanity check. Ditch it if you want faster performance
  140. if (!basetoken.equals(filetoken)) {
  141. throw new BuildException("File " + filename
  142. + " does not appear within " + absBase
  143. + "directory");
  144. }
  145. } else {
  146. depth += 1;
  147. if (max > -1 && depth > max) {
  148. return false;
  149. }
  150. }
  151. }
  152. if (tokBase.hasMoreTokens()) {
  153. throw new BuildException("File " + filename
  154. + " is outside of " + absBase + "directory tree");
  155. }
  156. if (min > -1 && depth < min) {
  157. return false;
  158. }
  159. return true;
  160. }
  161. }