14fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/*
24fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Licensed to the Apache Software Foundation (ASF) under one or more
34fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * contributor license agreements.  See the NOTICE file distributed with
44fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * this work for additional information regarding copyright ownership.
54fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The ASF licenses this file to You under the Apache License, Version 2.0
64fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * (the "License"); you may not use this file except in compliance with
74fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * the License.  You may obtain a copy of the License at
84fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
94fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      http://www.apache.org/licenses/LICENSE-2.0
104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Unless required by applicable law or agreed to in writing, software
124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * distributed under the License is distributed on an "AS IS" BASIS,
134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * See the License for the specific language governing permissions and
154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * limitations under the License.
164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */
174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypackage org.apache.commons.io;
184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.File;
204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.FileFilter;
214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.IOException;
224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.util.Collection;
234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.commons.io.filefilter.FileFilterUtils;
254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.commons.io.filefilter.IOFileFilter;
264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.commons.io.filefilter.TrueFileFilter;
274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/**
294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Abstract class that walks through a directory hierarchy and provides
304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * subclasses with convenient hooks to add specific behaviour.
314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This class operates with a {@link FileFilter} and maximum depth to
334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * limit the files and direcories visited.
344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Commons IO supplies many common filter implementations in the
354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <a href="filefilter/package-summary.html"> filefilter</a> package.
364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The following sections describe:
384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *   <ul>
394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      <li><a href="#example">1. Example Implementation</a> - example
404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *          <code>FileCleaner</code> implementation.</li>
414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      <li><a href="#filter">2. Filter Example</a> - using
424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *          {@link FileFilter}(s) with <code>DirectoryWalker</code>.</li>
434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      <li><a href="#cancel">3. Cancellation</a> - how to implement cancellation
444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *          behaviour.</li>
454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *   </ul>
464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <a name="example"></a>
484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <h3>1. Example Implementation</h3>
494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * There are many possible extensions, for example, to delete all
514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * files and '.svn' directories, and return a list of deleted files:
524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <pre>
534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  public class FileCleaner extends DirectoryWalker {
544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    public FileCleaner() {
564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      super();
574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    public List clean(File startDirectory) {
604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      List results = new ArrayList();
614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      walk(startDirectory, results);
624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      return results;
634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    protected boolean handleDirectory(File directory, int depth, Collection results) {
664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      // delete svn directories and then skip
674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      if (".svn".equals(directory.getName())) {
684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        directory.delete();
694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        return false;
704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      } else {
714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        return true;
724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      }
734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    protected void handleFile(File file, int depth, Collection results) {
774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      // delete file and add to list of deleted
784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      file.delete();
794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      results.add(file);
804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  }
824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * </pre>
834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <a name="filter"></a>
854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <h3>2. Filter Example</h3>
864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Choosing which directories and files to process can be a key aspect
884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * of using this class. This information can be setup in three ways,
894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * via three different constructors.
904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The first option is to visit all directories and files.
924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This is achieved via the no-args constructor.
934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The second constructor option is to supply a single {@link FileFilter}
954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * that describes the files and directories to visit. Care must be taken
964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * with this option as the same filter is used for both directories
974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * and files.
984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * For example, if you wanted all directories which are not hidden
1004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * and files which end in ".txt":
1014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <pre>
1024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  public class FooDirectoryWalker extends DirectoryWalker {
1034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    public FooDirectoryWalker(FileFilter filter) {
1044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      super(filter, -1);
1054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
1064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  }
1074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  // Build up the filters and create the walker
1094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    // Create a filter for Non-hidden directories
1104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    IOFileFilter fooDirFilter =
1114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        FileFilterUtils.andFileFilter(FileFilterUtils.directoryFileFilter,
1124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *                                      HiddenFileFilter.VISIBLE);
1134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    // Create a filter for Files ending in ".txt"
1154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    IOFileFilter fooFileFilter =
1164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        FileFilterUtils.andFileFilter(FileFilterUtils.fileFileFilter,
1174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *                                      FileFilterUtils.suffixFileFilter(".txt"));
1184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    // Combine the directory and file filters using an OR condition
1204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    java.io.FileFilter fooFilter =
1214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        FileFilterUtils.orFileFilter(fooDirFilter, fooFileFilter);
1224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    // Use the filter to construct a DirectoryWalker implementation
1244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    FooDirectoryWalker walker = new FooDirectoryWalker(fooFilter);
1254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * </pre>
1264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
1274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The third constructor option is to specify separate filters, one for
1284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * directories and one for files. These are combined internally to form
1294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * the correct <code>FileFilter</code>, something which is very easy to
1304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * get wrong when attempted manually, particularly when trying to
1314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * express constructs like 'any file in directories named docs'.
1324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
1334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * For example, if you wanted all directories which are not hidden
1344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * and files which end in ".txt":
1354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <pre>
1364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  public class FooDirectoryWalker extends DirectoryWalker {
1374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    public FooDirectoryWalker(IOFileFilter dirFilter, IOFileFilter fileFilter) {
1384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      super(dirFilter, fileFilter, -1);
1394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
1404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  }
1414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  // Use the filters to construct the walker
1434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  FooDirectoryWalker walker = new FooDirectoryWalker(
1444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    HiddenFileFilter.VISIBLE,
1454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    FileFilterUtils.suffixFileFilter(".txt"),
1464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  );
1474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * </pre>
1484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This is much simpler than the previous example, and is why it is the preferred
1494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * option for filtering.
1504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <a name="cancel"></a>
1524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <h3>3. Cancellation</h3>
1534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The DirectoryWalker contains some of the logic required for cancel processing.
1554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Subclasses must complete the implementation.
1564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
1574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * What <code>DirectoryWalker</code> does provide for cancellation is:
1584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <ul>
1594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    <li>{@link CancelException} which can be thrown in any of the
1604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        <i>lifecycle</i> methods to stop processing.</li>
1614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    <li>The <code>walk()</code> method traps thrown {@link CancelException}
1624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        and calls the <code>handleCancelled()</code> method, providing
1634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        a place for custom cancel processing.</li>
1644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * </ul>
1654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
1664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Implementations need to provide:
1674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <ul>
1684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    <li>The decision logic on whether to cancel processing or not.</li>
1694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    <li>Constructing and throwing a {@link CancelException}.</li>
1704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    <li>Custom cancel processing in the <code>handleCancelled()</code> method.
1714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * </ul>
1724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
1734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Two possible scenarios are envisaged for cancellation:
1744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <ul>
1754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    <li><a href="#external">3.1 External / Mult-threaded</a> - cancellation being
1764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        decided/initiated by an external process.</li>
1774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    <li><a href="#internal">3.2 Internal</a> - cancellation being decided/initiated
1784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        from within a DirectoryWalker implementation.</li>
1794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * </ul>
1804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
1814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The following sections provide example implementations for these two different
1824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * scenarios.
1834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <a name="external"></a>
1854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <h4>3.1 External / Multi-threaded</h4>
1864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This example provides a public <code>cancel()</code> method that can be
1884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * called by another thread to stop the processing. A typical example use-case
1894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * would be a cancel button on a GUI. Calling this method sets a
1904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#36930">
1914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * volatile</a> flag to ensure it will work properly in a multi-threaded environment.
1924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The flag is returned by the <code>handleIsCancelled()</code> method, which
1934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * will cause the walk to stop immediately. The <code>handleCancelled()</code>
1944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * method will be the next, and last, callback method received once cancellation
1954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * has occurred.
1964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
1974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <pre>
1984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  public class FooDirectoryWalker extends DirectoryWalker {
1994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    private volatile boolean cancelled = false;
2014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    public void cancel() {
2034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        cancelled = true;
2044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
2054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    private void handleIsCancelled(File file, int depth, Collection results) {
2074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        return cancelled;
2084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
2094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
2114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        // implement processing required when a cancellation occurs
2124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
2134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  }
2144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * </pre>
2154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <a name="internal"></a>
2174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <h4>3.2 Internal</h4>
2184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This shows an example of how internal cancellation processing could be implemented.
2204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <b>Note</b> the decision logic and throwing a {@link CancelException} could be implemented
2214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * in any of the <i>lifecycle</i> methods.
2224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <pre>
2244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  public class BarDirectoryWalker extends DirectoryWalker {
2254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
2274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        // cancel if hidden directory
2284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        if (directory.isHidden()) {
2294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *            throw new CancelException(file, depth);
2304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        }
2314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        return true;
2324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
2334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    protected void handleFile(File file, int depth, Collection results) throws IOException {
2354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        // cancel if read-only file
2364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        if (!file.canWrite()) {
2374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *            throw new CancelException(file, depth);
2384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        }
2394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        results.add(file);
2404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
2414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
2434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *        // implement processing required when a cancellation occurs
2444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *    }
2454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *  }
2464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * </pre>
2474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
2484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @since Commons IO 1.3
2494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @version $Revision: 424748 $
2504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */
2514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypublic abstract class DirectoryWalker {
2524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * The file filter to use to filter files and directories.
2554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private final FileFilter filter;
2574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * The limit on the directory depth to walk.
2594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private final int depthLimit;
2614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Construct an instance with no filtering and unlimited <i>depth</i>.
2644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected DirectoryWalker() {
2664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(null, -1);
2674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Construct an instance with a filter and limit the <i>depth</i> navigated to.
2714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
2724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * The filter controls which files and directories will be navigated to as
2734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * part of the walk. The {@link FileFilterUtils} class is useful for combining
2744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * various filters together. A <code>null</code> filter means that no
2754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * filtering should occur and all files and directories will be visited.
2764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
2774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param filter  the filter to apply, null means visit all files
2784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depthLimit  controls how <i>deep</i> the hierarchy is
2794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *  navigated to (less than 0 means unlimited)
2804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected DirectoryWalker(FileFilter filter, int depthLimit) {
2824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this.filter = filter;
2834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this.depthLimit = depthLimit;
2844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Construct an instance with a directory and a file filter and an optional
2884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * limit on the <i>depth</i> navigated to.
2894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
2904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * The filters control which files and directories will be navigated to as part
2914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * of the walk. This constructor uses {@link FileFilterUtils#makeDirectoryOnly(IOFileFilter)}
2924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * and {@link FileFilterUtils#makeFileOnly(IOFileFilter)} internally to combine the filters.
2934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * A <code>null</code> filter means that no filtering should occur.
2944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
2954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param directoryFilter  the filter to apply to directories, null means visit all directories
2964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param fileFilter  the filter to apply to files, null means visit all files
2974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depthLimit  controls how <i>deep</i> the hierarchy is
2984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *  navigated to (less than 0 means unlimited)
2994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected DirectoryWalker(IOFileFilter directoryFilter, IOFileFilter fileFilter, int depthLimit) {
3014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (directoryFilter == null && fileFilter == null) {
3024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            this.filter = null;
3034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        } else {
3044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            directoryFilter = (directoryFilter != null ? directoryFilter : TrueFileFilter.TRUE);
3054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            fileFilter = (fileFilter != null ? fileFilter : TrueFileFilter.TRUE);
3064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            directoryFilter = FileFilterUtils.makeDirectoryOnly(directoryFilter);
3074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            fileFilter = FileFilterUtils.makeFileOnly(fileFilter);
3084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            this.filter = FileFilterUtils.orFileFilter(directoryFilter, fileFilter);
3094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
3104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this.depthLimit = depthLimit;
3114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    //-----------------------------------------------------------------------
3144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
3154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Internal method that walks the directory hierarchy in a depth-first manner.
3164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
3174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Users of this class do not need to call this method. This method will
3184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * be called automatically by another (public) method on the specific subclass.
3194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
3204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Writers of subclasses should call this method to start the directory walk.
3214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Once called, this method will emit events as it walks the hierarchy.
3224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * The event methods have the prefix <code>handle</code>.
3234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
3244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param startDirectory  the directory to start from, not null
3254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
3264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the start directory is null
3274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
3284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected final void walk(File startDirectory, Collection results) throws IOException {
3304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (startDirectory == null) {
3314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw new NullPointerException("Start Directory is null");
3324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
3334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        try {
3344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            handleStart(startDirectory, results);
3354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            walk(startDirectory, 0, results);
3364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            handleEnd(results);
3374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        } catch(CancelException cancel) {
3384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            handleCancelled(startDirectory, results, cancel);
3394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
3404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
3434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Main recursive method to examine the directory hierarchy.
3444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
3454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param directory  the directory to examine, not null
3464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depth  the directory level (starting directory = 0)
3474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
3484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
3494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private void walk(File directory, int depth, Collection results) throws IOException {
3514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        checkIfCancelled(directory, depth, results);
3524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (handleDirectory(directory, depth, results)) {
3534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            handleDirectoryStart(directory, depth, results);
3544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            int childDepth = depth + 1;
3554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (depthLimit < 0 || childDepth <= depthLimit) {
3564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                checkIfCancelled(directory, depth, results);
3574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                File[] childFiles = (filter == null ? directory.listFiles() : directory.listFiles(filter));
3584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                if (childFiles == null) {
3594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    handleRestricted(directory, childDepth, results);
3604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                } else {
3614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    for (int i = 0; i < childFiles.length; i++) {
3624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                        File childFile = childFiles[i];
3634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                        if (childFile.isDirectory()) {
3644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                            walk(childFile, childDepth, results);
3654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                        } else {
3664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                            checkIfCancelled(childFile, childDepth, results);
3674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                            handleFile(childFile, childDepth, results);
3684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                            checkIfCancelled(childFile, childDepth, results);
3694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                        }
3704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    }
3714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                }
3724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
3734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            handleDirectoryEnd(directory, depth, results);
3744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
3754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        checkIfCancelled(directory, depth, results);
3764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    //-----------------------------------------------------------------------
3794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
3804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Checks whether the walk has been cancelled by calling {@link #handleIsCancelled},
3814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * throwing a <code>CancelException</code> if it has.
3824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
3834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Writers of subclasses should not normally call this method as it is called
3844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * automatically by the walk of the tree. However, sometimes a single method,
3854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * typically {@link #handleFile}, may take a long time to run. In that case,
3864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * you may wish to check for cancellation by calling this method.
3874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
3884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the current file being processed
3894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depth  the current file level (starting directory = 0)
3904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
3914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
3924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected final void checkIfCancelled(File file, int depth, Collection results) throws IOException {
3944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (handleIsCancelled(file, depth, results)) {
3954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw new CancelException(file, depth);
3964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
3974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
4004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked to determine if the entire walk
4014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * operation should be immediately cancelled.
4024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
4034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This method should be implemented by those subclasses that want to
4044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * provide a public <code>cancel()</code> method available from another
4054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * thread. The design pattern for the subclass should be as follows:
4064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <pre>
4074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *  public class FooDirectoryWalker extends DirectoryWalker {
4084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *    private volatile boolean cancelled = false;
4094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
4104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *    public void cancel() {
4114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *        cancelled = true;
4124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *    }
4134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *    private void handleIsCancelled(File file, int depth, Collection results) {
4144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *        return cancelled;
4154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *    }
4164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *    protected void handleCancelled(File startDirectory,
4174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *              Collection results, CancelException cancel) {
4184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *        // implement processing required when a cancellation occurs
4194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *    }
4204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *  }
4214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * </pre>
4224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
4234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * If this method returns true, then the directory walk is immediately
4244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * cancelled. The next callback method will be {@link #handleCancelled}.
4254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
4264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation returns false.
4274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
4284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the file or directory being processed
4294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depth  the current directory level (starting directory = 0)
4304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
4314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return true if the walk has been cancelled
4324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
4334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
4344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected boolean handleIsCancelled(
4354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            File file, int depth, Collection results) throws IOException {
4364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // do nothing - overridable by subclass
4374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return false;  // not cancelled
4384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
4394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
4404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
4414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked when the operation is cancelled.
4424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * The file being processed when the cancellation occurred can be
4434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * obtained from the exception.
4444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
4454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation just re-throws the {@link CancelException}.
4464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
4474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param startDirectory  the directory that the walk started from
4484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
4494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param cancel  the exception throw to cancel further processing
4504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * containing details at the point of cancellation.
4514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
4524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
4534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected void handleCancelled(File startDirectory, Collection results,
4544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                       CancelException cancel) throws IOException {
4554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // re-throw exception - overridable by subclass
4564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        throw cancel;
4574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
4584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
4594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    //-----------------------------------------------------------------------
4604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
4614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked at the start of processing.
4624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
4634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation does nothing.
4644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
4654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param startDirectory  the directory to start from
4664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
4674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
4684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
4694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected void handleStart(File startDirectory, Collection results) throws IOException {
4704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // do nothing - overridable by subclass
4714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
4724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
4734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
4744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked to determine if a directory should be processed.
4754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
4764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This method returns a boolean to indicate if the directory should be examined or not.
4774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * If you return false, the entire directory and any subdirectories will be skipped.
4784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Note that this functionality is in addition to the filtering by file filter.
4794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
4804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation does nothing and returns true.
4814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
4824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param directory  the current directory being processed
4834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depth  the current directory level (starting directory = 0)
4844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
4854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return true to process this directory, false to skip this directory
4864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
4874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
4884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
4894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // do nothing - overridable by subclass
4904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return true;  // process directory
4914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
4924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
4934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
4944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked at the start of processing each directory.
4954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
4964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation does nothing.
4974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
4984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param directory  the current directory being processed
4994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depth  the current directory level (starting directory = 0)
5004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
5014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
5024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
5034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected void handleDirectoryStart(File directory, int depth, Collection results) throws IOException {
5044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // do nothing - overridable by subclass
5054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
5064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
5084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked for each (non-directory) file.
5094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
5104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation does nothing.
5114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
5124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the current file being processed
5134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depth  the current directory level (starting directory = 0)
5144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
5154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
5164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
5174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected void handleFile(File file, int depth, Collection results) throws IOException {
5184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // do nothing - overridable by subclass
5194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
5204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
5224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked for each restricted directory.
5234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
5244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation does nothing.
5254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
5264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param directory  the restricted directory
5274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depth  the current directory level (starting directory = 0)
5284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
5294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
5304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
5314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected void handleRestricted(File directory, int depth, Collection results) throws IOException  {
5324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // do nothing - overridable by subclass
5334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
5344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
5364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked at the end of processing each directory.
5374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
5384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation does nothing.
5394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
5404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param directory  the directory being processed
5414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param depth  the current directory level (starting directory = 0)
5424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
5434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
5444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
5454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected void handleDirectoryEnd(File directory, int depth, Collection results) throws IOException {
5464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // do nothing - overridable by subclass
5474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
5484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
5504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Overridable callback method invoked at the end of processing.
5514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * <p>
5524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * This implementation does nothing.
5534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
5544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param results  the collection of result objects, may be updated
5554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O Error occurs
5564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
5574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    protected void handleEnd(Collection results) throws IOException {
5584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // do nothing - overridable by subclass
5594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
5604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    //-----------------------------------------------------------------------
5624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
5634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * CancelException is thrown in DirectoryWalker to cancel the current
5644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * processing.
5654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
5664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public static class CancelException extends IOException {
5674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        /** Serialization id. */
5694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        private static final long serialVersionUID = 1347339620135041008L;
5704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        /** The file being processed when the exception was thrown. */
5724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        private File file;
5734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        /** The file depth when the exception was thrown. */
5744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        private int depth = -1;
5754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        /**
5774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * Constructs a <code>CancelException</code> with
5784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * the file and depth when cancellation occurred.
5794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         *
5804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * @param file  the file when the operation was cancelled, may be null
5814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * @param depth  the depth when the operation was cancelled, may be null
5824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         */
5834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        public CancelException(File file, int depth) {
5844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            this("Operation Cancelled", file, depth);
5854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
5864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
5874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        /**
5884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * Constructs a <code>CancelException</code> with
5894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * an appropriate message and the file and depth when
5904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * cancellation occurred.
5914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         *
5924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * @param message  the detail message
5934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * @param file  the file when the operation was cancelled
5944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * @param depth  the depth when the operation was cancelled
5954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         */
5964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        public CancelException(String message, File file, int depth) {
5974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            super(message);
5984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            this.file = file;
5994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            this.depth = depth;
6004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
6014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
6024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        /**
6034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * Return the file when the operation was cancelled.
6044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         *
6054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * @return the file when the operation was cancelled
6064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         */
6074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        public File getFile() {
6084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            return file;
6094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
6104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
6114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        /**
6124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * Return the depth when the operation was cancelled.
6134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         *
6144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         * @return the depth when the operation was cancelled
6154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy         */
6164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        public int getDepth() {
6174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            return depth;
6184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
6194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
6204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy}
621