1. /*
  2. * Copyright 2000-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.taskdefs.optional.depend;
  18. import java.io.File;
  19. import java.io.FileInputStream;
  20. import java.io.IOException;
  21. import java.util.Enumeration;
  22. import java.util.Stack;
  23. import java.util.Vector;
  24. /**
  25. * An iterator which iterates through the contents of a java directory. The
  26. * iterator should be created with the directory at the root of the Java
  27. * namespace.
  28. *
  29. */
  30. public class DirectoryIterator implements ClassFileIterator {
  31. /**
  32. * This is a stack of current iterators supporting the depth first
  33. * traversal of the directory tree.
  34. */
  35. private Stack enumStack;
  36. /**
  37. * The current directory iterator. As directories encounter lower level
  38. * directories, the current iterator is pushed onto the iterator stack
  39. * and a new iterator over the sub directory becomes the current
  40. * directory. This implements a depth first traversal of the directory
  41. * namespace.
  42. */
  43. private Enumeration currentEnum;
  44. /**
  45. * The length of the root directory. This is used to remove the root
  46. * directory from full paths.
  47. */
  48. private int rootLength;
  49. /**
  50. * Creates a directory iterator. The directory iterator is created to
  51. * scan the root directory. If the changeInto flag is given, then the
  52. * entries returned will be relative to this directory and not the
  53. * current directory.
  54. *
  55. * @param rootDirectory the root if the directory namespace which is to
  56. * be iterated over
  57. * @param changeInto if true then the returned entries will be relative
  58. * to the rootDirectory and not the current directory.
  59. * @exception IOException if there is a problem reading the directory
  60. * information.
  61. */
  62. public DirectoryIterator(File rootDirectory, boolean changeInto)
  63. throws IOException {
  64. super();
  65. enumStack = new Stack();
  66. if (rootDirectory.isAbsolute() || changeInto) {
  67. rootLength = rootDirectory.getPath().length() + 1;
  68. } else {
  69. rootLength = 0;
  70. }
  71. Vector filesInRoot = getDirectoryEntries(rootDirectory);
  72. currentEnum = filesInRoot.elements();
  73. }
  74. /**
  75. * Get a vector covering all the entries (files and subdirectories in a
  76. * directory).
  77. *
  78. * @param directory the directory to be scanned.
  79. * @return a vector containing File objects for each entry in the
  80. * directory.
  81. */
  82. private Vector getDirectoryEntries(File directory) {
  83. Vector files = new Vector();
  84. // File[] filesInDir = directory.listFiles();
  85. String[] filesInDir = directory.list();
  86. if (filesInDir != null) {
  87. int length = filesInDir.length;
  88. for (int i = 0; i < length; ++i) {
  89. files.addElement(new File(directory, filesInDir[i]));
  90. }
  91. }
  92. return files;
  93. }
  94. /**
  95. * Template method to allow subclasses to supply elements for the
  96. * iteration. The directory iterator maintains a stack of iterators
  97. * covering each level in the directory hierarchy. The current iterator
  98. * covers the current directory being scanned. If the next entry in that
  99. * directory is a subdirectory, the current iterator is pushed onto the
  100. * stack and a new iterator is created for the subdirectory. If the
  101. * entry is a file, it is returned as the next element and the iterator
  102. * remains valid. If there are no more entries in the current directory,
  103. * the topmost iterator on the stack is popped off to become the
  104. * current iterator.
  105. *
  106. * @return the next ClassFile in the iteration.
  107. */
  108. public ClassFile getNextClassFile() {
  109. ClassFile nextElement = null;
  110. try {
  111. while (nextElement == null) {
  112. if (currentEnum.hasMoreElements()) {
  113. File element = (File) currentEnum.nextElement();
  114. if (element.isDirectory()) {
  115. // push the current iterator onto the stack and then
  116. // iterate through this directory.
  117. enumStack.push(currentEnum);
  118. Vector files = getDirectoryEntries(element);
  119. currentEnum = files.elements();
  120. } else {
  121. // we have a file. create a stream for it
  122. FileInputStream inFileStream
  123. = new FileInputStream(element);
  124. if (element.getName().endsWith(".class")) {
  125. // create a data input stream from the jar
  126. // input stream
  127. ClassFile javaClass = new ClassFile();
  128. javaClass.read(inFileStream);
  129. nextElement = javaClass;
  130. }
  131. }
  132. } else {
  133. // this iterator is exhausted. Can we pop one off the stack
  134. if (enumStack.empty()) {
  135. break;
  136. } else {
  137. currentEnum = (Enumeration) enumStack.pop();
  138. }
  139. }
  140. }
  141. } catch (IOException e) {
  142. nextElement = null;
  143. }
  144. return nextElement;
  145. }
  146. }