001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package makedep;
028:
029: /** Encapsulates a notion of a directory tree. Designed to allow fast
030: querying of full paths for unique filenames in the hierarchy. */
031:
032: import java.io.*;
033: import java.util.*;
034:
035: public class DirectoryTree {
036:
037: /** The root of the read directoryTree */
038: private Node rootNode;
039:
040: /** Subdirs to ignore; Vector of Strings */
041: private Vector subdirsToIgnore;
042:
043: /** This maps file names to Lists of nodes. */
044: private Hashtable nameToNodeListTable;
045:
046: /** Output "."'s as directories are read. Defaults to false. */
047: private boolean verbose;
048:
049: public DirectoryTree() {
050: subdirsToIgnore = new Vector();
051: verbose = false;
052: }
053:
054: /** Takes an absolute path to the root directory of this
055: DirectoryTree. Throws IllegalArgumentException if the given
056: string represents a plain file or nonexistent directory. */
057:
058: public DirectoryTree(String baseDirectory) {
059: this ();
060: readDirectory(baseDirectory);
061: }
062:
063: public void addSubdirToIgnore(String subdir) {
064: subdirsToIgnore.add(subdir);
065: }
066:
067: /** Output "."'s to System.out as directories are read. Defaults
068: to false. */
069: public void setVerbose(boolean newValue) {
070: verbose = newValue;
071: }
072:
073: public boolean getVerbose() {
074: return verbose;
075: }
076:
077: /** Takes an absolute path to the root directory of this
078: DirectoryTree. Throws IllegalArgumentException if the given
079: string represents a plain file or nonexistent directory. */
080:
081: public void readDirectory(String baseDirectory)
082: throws IllegalArgumentException {
083: File root = new File(baseDirectory);
084: if (!root.isDirectory()) {
085: throw new IllegalArgumentException("baseDirectory \""
086: + baseDirectory + "\" does not exist or "
087: + "is not a directory");
088: }
089: try {
090: root = root.getCanonicalFile();
091: } catch (IOException e) {
092: throw new RuntimeException(e.toString());
093: }
094: rootNode = new Node(root);
095: readDirectory(rootNode, root);
096: }
097:
098: /** Queries the DirectoryTree for a file or directory name. Takes
099: only the name of the file or directory itself (i.e., no parent
100: directory information should be in the passed name). Returns a
101: List of DirectoryTreeNodes specifying the full paths of all of
102: the files or directories of this name in the DirectoryTree.
103: Returns null if the directory tree has not been read from disk
104: yet or if the file was not found in the tree. */
105: public List findFile(String name) {
106: if (rootNode == null) {
107: return null;
108: }
109:
110: if (nameToNodeListTable == null) {
111: nameToNodeListTable = new Hashtable();
112: try {
113: buildNameToNodeListTable(rootNode);
114: } catch (IOException e) {
115: e.printStackTrace();
116: return null;
117: }
118: }
119:
120: return (List) nameToNodeListTable.get(name);
121: }
122:
123: private void buildNameToNodeListTable(Node curNode)
124: throws IOException {
125: String fullName = curNode.getName();
126: String parent = curNode.getParent();
127: String separator = System.getProperty("file.separator");
128:
129: if (parent != null) {
130: if (!fullName.startsWith(parent)) {
131: throw new RuntimeException(
132: "Internal error: parent of file name \""
133: + fullName
134: + "\" does not match file name \""
135: + parent + "\"");
136: }
137:
138: int len = parent.length();
139: if (!parent.endsWith(separator)) {
140: len += separator.length();
141: }
142:
143: String fileName = fullName.substring(len);
144:
145: if (fileName == null) {
146: throw new RuntimeException(
147: "Internal error: file name was empty");
148: }
149:
150: List nodeList = (List) nameToNodeListTable.get(fileName);
151: if (nodeList == null) {
152: nodeList = new Vector();
153: nameToNodeListTable.put(fileName, nodeList);
154: }
155:
156: nodeList.add(curNode);
157: } else {
158: if (curNode != rootNode) {
159: throw new RuntimeException(
160: "Internal error: parent of file + \""
161: + fullName + "\"" + " was null");
162: }
163: }
164:
165: if (curNode.isDirectory()) {
166: Iterator iter = curNode.getChildren();
167: if (iter != null) {
168: while (iter.hasNext()) {
169: buildNameToNodeListTable((Node) iter.next());
170: }
171: }
172: }
173: }
174:
175: /** Reads all of the files in the given directory and adds them as
176: children of the directory tree node. Requires that the passed
177: node represents a directory. */
178:
179: private void readDirectory(Node parentNode, File parentDir) {
180: File[] children = parentDir.listFiles();
181: if (children == null)
182: return;
183: if (verbose) {
184: System.out.print(".");
185: System.out.flush();
186: }
187: for (int i = 0; i < children.length; i++) {
188: File child = children[i];
189: children[i] = null;
190: boolean isDir = child.isDirectory();
191: boolean mustSkip = false;
192: if (isDir) {
193: for (Iterator iter = subdirsToIgnore.iterator(); iter
194: .hasNext();) {
195: if (child.getName().equals((String) iter.next())) {
196: mustSkip = true;
197: break;
198: }
199: }
200: }
201: if (!mustSkip) {
202: Node childNode = new Node(child);
203: parentNode.addChild(childNode);
204: if (isDir) {
205: readDirectory(childNode, child);
206: }
207: }
208: }
209: }
210:
211: private class Node implements DirectoryTreeNode {
212: private File file;
213: private Vector children;
214:
215: /** file must be a canonical file */
216: Node(File file) {
217: this .file = file;
218: children = new Vector();
219: }
220:
221: public boolean isFile() {
222: return file.isFile();
223: }
224:
225: public boolean isDirectory() {
226: return file.isDirectory();
227: }
228:
229: public String getName() {
230: return file.getPath();
231: }
232:
233: public String getParent() {
234: return file.getParent();
235: }
236:
237: public void addChild(Node n) {
238: children.add(n);
239: }
240:
241: public Iterator getChildren() throws IllegalArgumentException {
242: return children.iterator();
243: }
244:
245: public int getNumChildren() throws IllegalArgumentException {
246: return children.size();
247: }
248:
249: public DirectoryTreeNode getChild(int i)
250: throws IllegalArgumentException,
251: ArrayIndexOutOfBoundsException {
252: return (DirectoryTreeNode) children.get(i);
253: }
254: }
255: }
|