Coverage Report - org.apache.commons.io.DirectoryWalker
 
Classes in this File Line Coverage Branch Coverage Complexity
DirectoryWalker
98%
56/57
100%
26/26
1.85
DirectoryWalker$CancelException
100%
8/8
N/A
1.85
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.io;
 18  
 
 19  
 import java.io.File;
 20  
 import java.io.FileFilter;
 21  
 import java.io.IOException;
 22  
 import java.util.Collection;
 23  
 
 24  
 import org.apache.commons.io.filefilter.FileFilterUtils;
 25  
 import org.apache.commons.io.filefilter.IOFileFilter;
 26  
 import org.apache.commons.io.filefilter.TrueFileFilter;
 27  
 
 28  
 /**
 29  
  * Abstract class that walks through a directory hierarchy and provides
 30  
  * subclasses with convenient hooks to add specific behaviour.
 31  
  * <p>
 32  
  * This class operates with a {@link FileFilter} and maximum depth to
 33  
  * limit the files and direcories visited.
 34  
  * Commons IO supplies many common filter implementations in the
 35  
  * <a href="filefilter/package-summary.html"> filefilter</a> package.
 36  
  * <p>
 37  
  * The following sections describe:
 38  
  *   <ul>
 39  
  *      <li><a href="#example">1. Example Implementation</a> - example
 40  
  *          <code>FileCleaner</code> implementation.</li>
 41  
  *      <li><a href="#filter">2. Filter Example</a> - using
 42  
  *          {@link FileFilter}(s) with <code>DirectoryWalker</code>.</li>
 43  
  *      <li><a href="#cancel">3. Cancellation</a> - how to implement cancellation
 44  
  *          behaviour.</li>
 45  
  *   </ul>
 46  
  *
 47  
  * <a name="example"></a>
 48  
  * <h3>1. Example Implementation</h3>
 49  
  *
 50  
  * There are many possible extensions, for example, to delete all
 51  
  * files and '.svn' directories, and return a list of deleted files:
 52  
  * <pre>
 53  
  *  public class FileCleaner extends DirectoryWalker {
 54  
  *
 55  
  *    public FileCleaner() {
 56  
  *      super();
 57  
  *    }
 58  
  *
 59  
  *    public List clean(File startDirectory) {
 60  
  *      List results = new ArrayList();
 61  
  *      walk(startDirectory, results);
 62  
  *      return results;
 63  
  *    }
 64  
  *
 65  
  *    protected boolean handleDirectory(File directory, int depth, Collection results) {
 66  
  *      // delete svn directories and then skip
 67  
  *      if (".svn".equals(directory.getName())) {
 68  
  *        directory.delete();
 69  
  *        return false;
 70  
  *      } else {
 71  
  *        return true;
 72  
  *      }
 73  
  *
 74  
  *    }
 75  
  *
 76  
  *    protected void handleFile(File file, int depth, Collection results) {
 77  
  *      // delete file and add to list of deleted
 78  
  *      file.delete();
 79  
  *      results.add(file);
 80  
  *    }
 81  
  *  }
 82  
  * </pre>
 83  
  *
 84  
  * <a name="filter"></a>
 85  
  * <h3>2. Filter Example</h3>
 86  
  *
 87  
  * Choosing which directories and files to process can be a key aspect
 88  
  * of using this class. This information can be setup in three ways,
 89  
  * via three different constructors.
 90  
  * <p>
 91  
  * The first option is to visit all directories and files.
 92  
  * This is achieved via the no-args constructor.
 93  
  * <p>
 94  
  * The second constructor option is to supply a single {@link FileFilter}
 95  
  * that describes the files and directories to visit. Care must be taken
 96  
  * with this option as the same filter is used for both directories
 97  
  * and files.
 98  
  * <p>
 99  
  * For example, if you wanted all directories which are not hidden
 100  
  * and files which end in ".txt":
 101  
  * <pre>
 102  
  *  public class FooDirectoryWalker extends DirectoryWalker {
 103  
  *    public FooDirectoryWalker(FileFilter filter) {
 104  
  *      super(filter, -1);
 105  
  *    }
 106  
  *  }
 107  
  *
 108  
  *  // Build up the filters and create the walker
 109  
  *    // Create a filter for Non-hidden directories
 110  
  *    IOFileFilter fooDirFilter =
 111  
  *        FileFilterUtils.andFileFilter(FileFilterUtils.directoryFileFilter,
 112  
  *                                      HiddenFileFilter.VISIBLE);
 113  
  *
 114  
  *    // Create a filter for Files ending in ".txt"
 115  
  *    IOFileFilter fooFileFilter =
 116  
  *        FileFilterUtils.andFileFilter(FileFilterUtils.fileFileFilter,
 117  
  *                                      FileFilterUtils.suffixFileFilter(".txt"));
 118  
  *
 119  
  *    // Combine the directory and file filters using an OR condition
 120  
  *    java.io.FileFilter fooFilter =
 121  
  *        FileFilterUtils.orFileFilter(fooDirFilter, fooFileFilter);
 122  
  *
 123  
  *    // Use the filter to construct a DirectoryWalker implementation
 124  
  *    FooDirectoryWalker walker = new FooDirectoryWalker(fooFilter);
 125  
  * </pre>
 126  
  * <p>
 127  
  * The third constructor option is to specify separate filters, one for
 128  
  * directories and one for files. These are combined internally to form
 129  
  * the correct <code>FileFilter</code>, something which is very easy to
 130  
  * get wrong when attempted manually, particularly when trying to
 131  
  * express constructs like 'any file in directories named docs'.
 132  
  * <p>
 133  
  * For example, if you wanted all directories which are not hidden
 134  
  * and files which end in ".txt":
 135  
  * <pre>
 136  
  *  public class FooDirectoryWalker extends DirectoryWalker {
 137  
  *    public FooDirectoryWalker(IOFileFilter dirFilter, IOFileFilter fileFilter) {
 138  
  *      super(dirFilter, fileFilter, -1);
 139  
  *    }
 140  
  *  }
 141  
  *
 142  
  *  // Use the filters to construct the walker
 143  
  *  FooDirectoryWalker walker = new FooDirectoryWalker(
 144  
  *    HiddenFileFilter.VISIBLE,
 145  
  *    FileFilterUtils.suffixFileFilter(".txt"),
 146  
  *  );
 147  
  * </pre>
 148  
  * This is much simpler than the previous example, and is why it is the preferred
 149  
  * option for filtering.
 150  
  *
 151  
  * <a name="cancel"></a>
 152  
  * <h3>3. Cancellation</h3>
 153  
  *
 154  
  * The DirectoryWalker contains some of the logic required for cancel processing.
 155  
  * Subclasses must complete the implementation.
 156  
  * <p>
 157  
  * What <code>DirectoryWalker</code> does provide for cancellation is:
 158  
  * <ul>
 159  
  *    <li>{@link CancelException} which can be thrown in any of the
 160  
  *        <i>lifecycle</i> methods to stop processing.</li>
 161  
  *    <li>The <code>walk()</code> method traps thrown {@link CancelException}
 162  
  *        and calls the <code>handleCancelled()</code> method, providing
 163  
  *        a place for custom cancel processing.</li>
 164  
  * </ul>
 165  
  * <p>
 166  
  * Implementations need to provide:
 167  
  * <ul>
 168  
  *    <li>The decision logic on whether to cancel processing or not.</li>
 169  
  *    <li>Constructing and throwing a {@link CancelException}.</li>
 170  
  *    <li>Custom cancel processing in the <code>handleCancelled()</code> method.
 171  
  * </ul>
 172  
  * <p>
 173  
  * Two possible scenarios are envisaged for cancellation:
 174  
  * <ul>
 175  
  *    <li><a href="#external">3.1 External / Mult-threaded</a> - cancellation being
 176  
  *        decided/initiated by an external process.</li>
 177  
  *    <li><a href="#internal">3.2 Internal</a> - cancellation being decided/initiated
 178  
  *        from within a DirectoryWalker implementation.</li>
 179  
  * </ul>
 180  
  * <p>
 181  
  * The following sections provide example implementations for these two different
 182  
  * scenarios.
 183  
  *
 184  
  * <a name="external"></a>
 185  
  * <h4>3.1 External / Multi-threaded</h4>
 186  
  *
 187  
  * This example provides a public <code>cancel()</code> method that can be
 188  
  * called by another thread to stop the processing. A typical example use-case
 189  
  * would be a cancel button on a GUI. Calling this method sets a
 190  
  * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#36930">
 191  
  * volatile</a> flag to ensure it will work properly in a multi-threaded environment.
 192  
  * The flag is returned by the <code>handleIsCancelled()</code> method, which
 193  
  * will cause the walk to stop immediately. The <code>handleCancelled()</code>
 194  
  * method will be the next, and last, callback method received once cancellation
 195  
  * has occurred.
 196  
  *
 197  
  * <pre>
 198  
  *  public class FooDirectoryWalker extends DirectoryWalker {
 199  
  *
 200  
  *    private volatile boolean cancelled = false;
 201  
  *
 202  
  *    public void cancel() {
 203  
  *        cancelled = true;
 204  
  *    }
 205  
  *
 206  
  *    private void handleIsCancelled(File file, int depth, Collection results) {
 207  
  *        return cancelled;
 208  
  *    }
 209  
  *
 210  
  *    protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
 211  
  *        // implement processing required when a cancellation occurs
 212  
  *    }
 213  
  *  }
 214  
  * </pre>
 215  
  *
 216  
  * <a name="internal"></a>
 217  
  * <h4>3.2 Internal</h4>
 218  
  *
 219  
  * This shows an example of how internal cancellation processing could be implemented.
 220  
  * <b>Note</b> the decision logic and throwing a {@link CancelException} could be implemented
 221  
  * in any of the <i>lifecycle</i> methods.
 222  
  *
 223  
  * <pre>
 224  
  *  public class BarDirectoryWalker extends DirectoryWalker {
 225  
  *
 226  
  *    protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
 227  
  *        // cancel if hidden directory
 228  
  *        if (directory.isHidden()) {
 229  
  *            throw new CancelException(file, depth);
 230  
  *        }
 231  
  *        return true;
 232  
  *    }
 233  
  *
 234  
  *    protected void handleFile(File file, int depth, Collection results) throws IOException {
 235  
  *        // cancel if read-only file
 236  
  *        if (!file.canWrite()) {
 237  
  *            throw new CancelException(file, depth);
 238  
  *        }
 239  
  *        results.add(file);
 240  
  *    }
 241  
  *
 242  
  *    protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
 243  
  *        // implement processing required when a cancellation occurs
 244  
  *    }
 245  
  *  }
 246  
  * </pre>
 247  
  *
 248  
  * @since 1.3
 249  
  * @version $Id: DirectoryWalker.java 1515386 2013-08-19 12:29:24Z sebb $
 250  
  */
 251  
 public abstract class DirectoryWalker<T> {
 252  
 
 253  
     /**
 254  
      * The file filter to use to filter files and directories.
 255  
      */
 256  
     private final FileFilter filter;
 257  
     /**
 258  
      * The limit on the directory depth to walk.
 259  
      */
 260  
     private final int depthLimit;
 261  
 
 262  
     /**
 263  
      * Construct an instance with no filtering and unlimited <i>depth</i>.
 264  
      */
 265  
     protected DirectoryWalker() {
 266  26
         this(null, -1);
 267  26
     }
 268  
 
 269  
     /**
 270  
      * Construct an instance with a filter and limit the <i>depth</i> navigated to.
 271  
      * <p>
 272  
      * The filter controls which files and directories will be navigated to as
 273  
      * part of the walk. The {@link FileFilterUtils} class is useful for combining
 274  
      * various filters together. A {@code null} filter means that no
 275  
      * filtering should occur and all files and directories will be visited.
 276  
      *
 277  
      * @param filter  the filter to apply, null means visit all files
 278  
      * @param depthLimit  controls how <i>deep</i> the hierarchy is
 279  
      *  navigated to (less than 0 means unlimited)
 280  
      */
 281  64
     protected DirectoryWalker(final FileFilter filter, final int depthLimit) {
 282  64
         this.filter = filter;
 283  64
         this.depthLimit = depthLimit;
 284  64
     }
 285  
 
 286  
     /**
 287  
      * Construct an instance with a directory and a file filter and an optional
 288  
      * limit on the <i>depth</i> navigated to.
 289  
      * <p>
 290  
      * The filters control which files and directories will be navigated to as part
 291  
      * of the walk. This constructor uses {@link FileFilterUtils#makeDirectoryOnly(IOFileFilter)}
 292  
      * and {@link FileFilterUtils#makeFileOnly(IOFileFilter)} internally to combine the filters.
 293  
      * A {@code null} filter means that no filtering should occur.
 294  
      *
 295  
      * @param directoryFilter  the filter to apply to directories, null means visit all directories
 296  
      * @param fileFilter  the filter to apply to files, null means visit all files
 297  
      * @param depthLimit  controls how <i>deep</i> the hierarchy is
 298  
      *  navigated to (less than 0 means unlimited)
 299  
      */
 300  16
     protected DirectoryWalker(IOFileFilter directoryFilter, IOFileFilter fileFilter, final int depthLimit) {
 301  16
         if (directoryFilter == null && fileFilter == null) {
 302  4
             this.filter = null;
 303  
         } else {
 304  12
             directoryFilter = directoryFilter != null ? directoryFilter : TrueFileFilter.TRUE;
 305  12
             fileFilter = fileFilter != null ? fileFilter : TrueFileFilter.TRUE;
 306  12
             directoryFilter = FileFilterUtils.makeDirectoryOnly(directoryFilter);
 307  12
             fileFilter = FileFilterUtils.makeFileOnly(fileFilter);
 308  12
             this.filter = FileFilterUtils.or(directoryFilter, fileFilter);
 309  
         }
 310  16
         this.depthLimit = depthLimit;
 311  16
     }
 312  
 
 313  
     //-----------------------------------------------------------------------
 314  
     /**
 315  
      * Internal method that walks the directory hierarchy in a depth-first manner.
 316  
      * <p>
 317  
      * Users of this class do not need to call this method. This method will
 318  
      * be called automatically by another (public) method on the specific subclass.
 319  
      * <p>
 320  
      * Writers of subclasses should call this method to start the directory walk.
 321  
      * Once called, this method will emit events as it walks the hierarchy.
 322  
      * The event methods have the prefix <code>handle</code>.
 323  
      *
 324  
      * @param startDirectory  the directory to start from, not null
 325  
      * @param results  the collection of result objects, may be updated
 326  
      * @throws NullPointerException if the start directory is null
 327  
      * @throws IOException if an I/O Error occurs
 328  
      */
 329  
     protected final void walk(final File startDirectory, final Collection<T> results) throws IOException {
 330  92
         if (startDirectory == null) {
 331  4
             throw new NullPointerException("Start Directory is null");
 332  
         }
 333  
         try {
 334  88
             handleStart(startDirectory, results);
 335  88
             walk(startDirectory, 0, results);
 336  64
             handleEnd(results);
 337  24
         } catch(final CancelException cancel) {
 338  24
             handleCancelled(startDirectory, results, cancel);
 339  64
         }
 340  72
     }
 341  
 
 342  
     /**
 343  
      * Main recursive method to examine the directory hierarchy.
 344  
      *
 345  
      * @param directory  the directory to examine, not null
 346  
      * @param depth  the directory level (starting directory = 0)
 347  
      * @param results  the collection of result objects, may be updated
 348  
      * @throws IOException if an I/O Error occurs
 349  
      */
 350  
     private void walk(final File directory, final int depth, final Collection<T> results) throws IOException {
 351  522
         checkIfCancelled(directory, depth, results);
 352  522
         if (handleDirectory(directory, depth, results)) {
 353  518
             handleDirectoryStart(directory, depth, results);
 354  518
             final int childDepth = depth + 1;
 355  518
             if (depthLimit < 0 || childDepth <= depthLimit) {
 356  498
                 checkIfCancelled(directory, depth, results);
 357  498
                 File[] childFiles = filter == null ? directory.listFiles() : directory.listFiles(filter);
 358  498
                 childFiles = filterDirectoryContents(directory, depth, childFiles);
 359  498
                 if (childFiles == null) {
 360  4
                     handleRestricted(directory, childDepth, results);
 361  
                 } else {
 362  3502
                     for (final File childFile : childFiles) {
 363  3096
                         if (childFile.isDirectory()) {
 364  434
                             walk(childFile, childDepth, results);
 365  
                         } else {
 366  2662
                             checkIfCancelled(childFile, childDepth, results);
 367  2662
                             handleFile(childFile, childDepth, results);
 368  2658
                             checkIfCancelled(childFile, childDepth, results);
 369  
                         }
 370  
                     }
 371  
                 }
 372  
             }
 373  430
             handleDirectoryEnd(directory, depth, results);
 374  
         }
 375  426
         checkIfCancelled(directory, depth, results);
 376  418
     }
 377  
 
 378  
     //-----------------------------------------------------------------------
 379  
     /**
 380  
      * Checks whether the walk has been cancelled by calling {@link #handleIsCancelled},
 381  
      * throwing a <code>CancelException</code> if it has.
 382  
      * <p>
 383  
      * Writers of subclasses should not normally call this method as it is called
 384  
      * automatically by the walk of the tree. However, sometimes a single method,
 385  
      * typically {@link #handleFile}, may take a long time to run. In that case,
 386  
      * you may wish to check for cancellation by calling this method.
 387  
      *
 388  
      * @param file  the current file being processed
 389  
      * @param depth  the current file level (starting directory = 0)
 390  
      * @param results  the collection of result objects, may be updated
 391  
      * @throws IOException if an I/O Error occurs
 392  
      */
 393  
     protected final void checkIfCancelled(final File file, final int depth, final Collection<T> results) throws IOException {
 394  6766
         if (handleIsCancelled(file, depth, results)) {
 395  12
             throw new CancelException(file, depth);
 396  
         }
 397  6754
     }
 398  
 
 399  
     /**
 400  
      * Overridable callback method invoked to determine if the entire walk
 401  
      * operation should be immediately cancelled.
 402  
      * <p>
 403  
      * This method should be implemented by those subclasses that want to
 404  
      * provide a public <code>cancel()</code> method available from another
 405  
      * thread. The design pattern for the subclass should be as follows:
 406  
      * <pre>
 407  
      *  public class FooDirectoryWalker extends DirectoryWalker {
 408  
      *    private volatile boolean cancelled = false;
 409  
      *
 410  
      *    public void cancel() {
 411  
      *        cancelled = true;
 412  
      *    }
 413  
      *    private void handleIsCancelled(File file, int depth, Collection results) {
 414  
      *        return cancelled;
 415  
      *    }
 416  
      *    protected void handleCancelled(File startDirectory,
 417  
      *              Collection results, CancelException cancel) {
 418  
      *        // implement processing required when a cancellation occurs
 419  
      *    }
 420  
      *  }
 421  
      * </pre>
 422  
      * <p>
 423  
      * If this method returns true, then the directory walk is immediately
 424  
      * cancelled. The next callback method will be {@link #handleCancelled}.
 425  
      * <p>
 426  
      * This implementation returns false.
 427  
      *
 428  
      * @param file  the file or directory being processed
 429  
      * @param depth  the current directory level (starting directory = 0)
 430  
      * @param results  the collection of result objects, may be updated
 431  
      * @return true if the walk has been cancelled
 432  
      * @throws IOException if an I/O Error occurs
 433  
      */
 434  
     protected boolean handleIsCancelled(
 435  
             final File file, final int depth, final Collection<T> results) throws IOException {
 436  
         // do nothing - overridable by subclass
 437  4586
         return false;  // not cancelled
 438  
     }
 439  
 
 440  
     /**
 441  
      * Overridable callback method invoked when the operation is cancelled.
 442  
      * The file being processed when the cancellation occurred can be
 443  
      * obtained from the exception.
 444  
      * <p>
 445  
      * This implementation just re-throws the {@link CancelException}.
 446  
      *
 447  
      * @param startDirectory  the directory that the walk started from
 448  
      * @param results  the collection of result objects, may be updated
 449  
      * @param cancel  the exception throw to cancel further processing
 450  
      * containing details at the point of cancellation.
 451  
      * @throws IOException if an I/O Error occurs
 452  
      */
 453  
     protected void handleCancelled(final File startDirectory, final Collection<T> results,
 454  
                        final CancelException cancel) throws IOException {
 455  
         // re-throw exception - overridable by subclass
 456  16
         throw cancel;
 457  
     }
 458  
 
 459  
     //-----------------------------------------------------------------------
 460  
     /**
 461  
      * Overridable callback method invoked at the start of processing.
 462  
      * <p>
 463  
      * This implementation does nothing.
 464  
      *
 465  
      * @param startDirectory  the directory to start from
 466  
      * @param results  the collection of result objects, may be updated
 467  
      * @throws IOException if an I/O Error occurs
 468  
      */
 469  
     protected void handleStart(final File startDirectory, final Collection<T> results) throws IOException {
 470  
         // do nothing - overridable by subclass
 471  88
     }
 472  
 
 473  
     /**
 474  
      * Overridable callback method invoked to determine if a directory should be processed.
 475  
      * <p>
 476  
      * This method returns a boolean to indicate if the directory should be examined or not.
 477  
      * If you return false, the entire directory and any subdirectories will be skipped.
 478  
      * Note that this functionality is in addition to the filtering by file filter.
 479  
      * <p>
 480  
      * This implementation does nothing and returns true.
 481  
      *
 482  
      * @param directory  the current directory being processed
 483  
      * @param depth  the current directory level (starting directory = 0)
 484  
      * @param results  the collection of result objects, may be updated
 485  
      * @return true to process this directory, false to skip this directory
 486  
      * @throws IOException if an I/O Error occurs
 487  
      */
 488  
     protected boolean handleDirectory(final File directory, final int depth, final Collection<T> results) throws IOException {
 489  
         // do nothing - overridable by subclass
 490  518
         return true;  // process directory
 491  
     }
 492  
 
 493  
     /**
 494  
      * Overridable callback method invoked at the start of processing each directory.
 495  
      * <p>
 496  
      * This implementation does nothing.
 497  
      *
 498  
      * @param directory  the current directory being processed
 499  
      * @param depth  the current directory level (starting directory = 0)
 500  
      * @param results  the collection of result objects, may be updated
 501  
      * @throws IOException if an I/O Error occurs
 502  
      */
 503  
     protected void handleDirectoryStart(final File directory, final int depth, final Collection<T> results) throws IOException {
 504  
         // do nothing - overridable by subclass
 505  432
     }
 506  
 
 507  
     /**
 508  
      * Overridable callback method invoked with the contents of each directory.
 509  
      * <p>
 510  
      * This implementation returns the files unchanged
 511  
      *
 512  
      * @param directory  the current directory being processed
 513  
      * @param depth  the current directory level (starting directory = 0)
 514  
      * @param files the files (possibly filtered) in the directory, may be {@code null}
 515  
      * @return the filtered list of files
 516  
      * @throws IOException if an I/O Error occurs
 517  
      * @since 2.0
 518  
      */
 519  
     protected File[] filterDirectoryContents(final File directory, final int depth, final File[] files) throws IOException {
 520  498
         return files;
 521  
     }
 522  
 
 523  
     /**
 524  
      * Overridable callback method invoked for each (non-directory) file.
 525  
      * <p>
 526  
      * This implementation does nothing.
 527  
      *
 528  
      * @param file  the current file being processed
 529  
      * @param depth  the current directory level (starting directory = 0)
 530  
      * @param results  the collection of result objects, may be updated
 531  
      * @throws IOException if an I/O Error occurs
 532  
      */
 533  
     protected void handleFile(final File file, final int depth, final Collection<T> results) throws IOException {
 534  
         // do nothing - overridable by subclass
 535  0
     }
 536  
 
 537  
     /**
 538  
      * Overridable callback method invoked for each restricted directory.
 539  
      * <p>
 540  
      * This implementation does nothing.
 541  
      *
 542  
      * @param directory  the restricted directory
 543  
      * @param depth  the current directory level (starting directory = 0)
 544  
      * @param results  the collection of result objects, may be updated
 545  
      * @throws IOException if an I/O Error occurs
 546  
      */
 547  
     protected void handleRestricted(final File directory, final int depth, final Collection<T> results) throws IOException  {
 548  
         // do nothing - overridable by subclass
 549  4
     }
 550  
 
 551  
     /**
 552  
      * Overridable callback method invoked at the end of processing each directory.
 553  
      * <p>
 554  
      * This implementation does nothing.
 555  
      *
 556  
      * @param directory  the directory being processed
 557  
      * @param depth  the current directory level (starting directory = 0)
 558  
      * @param results  the collection of result objects, may be updated
 559  
      * @throws IOException if an I/O Error occurs
 560  
      */
 561  
     protected void handleDirectoryEnd(final File directory, final int depth, final Collection<T> results) throws IOException {
 562  
         // do nothing - overridable by subclass
 563  98
     }
 564  
 
 565  
     /**
 566  
      * Overridable callback method invoked at the end of processing.
 567  
      * <p>
 568  
      * This implementation does nothing.
 569  
      *
 570  
      * @param results  the collection of result objects, may be updated
 571  
      * @throws IOException if an I/O Error occurs
 572  
      */
 573  
     protected void handleEnd(final Collection<T> results) throws IOException {
 574  
         // do nothing - overridable by subclass
 575  64
     }
 576  
 
 577  
     //-----------------------------------------------------------------------
 578  
     /**
 579  
      * CancelException is thrown in DirectoryWalker to cancel the current
 580  
      * processing.
 581  
      */
 582  
     public static class CancelException extends IOException {
 583  
 
 584  
         /** Serialization id. */
 585  
         private static final long serialVersionUID = 1347339620135041008L;
 586  
 
 587  
         /** The file being processed when the exception was thrown. */
 588  
         private final File file;
 589  
         /** The file depth when the exception was thrown. */
 590  
         private final int depth;
 591  
 
 592  
         /**
 593  
          * Constructs a <code>CancelException</code> with
 594  
          * the file and depth when cancellation occurred.
 595  
          *
 596  
          * @param file  the file when the operation was cancelled, may be null
 597  
          * @param depth  the depth when the operation was cancelled, may be null
 598  
          */
 599  
         public CancelException(final File file, final int depth) {
 600  24
             this("Operation Cancelled", file, depth);
 601  24
         }
 602  
 
 603  
         /**
 604  
          * Constructs a <code>CancelException</code> with
 605  
          * an appropriate message and the file and depth when
 606  
          * cancellation occurred.
 607  
          *
 608  
          * @param message  the detail message
 609  
          * @param file  the file when the operation was cancelled
 610  
          * @param depth  the depth when the operation was cancelled
 611  
          */
 612  
         public CancelException(final String message, final File file, final int depth) {
 613  24
             super(message);
 614  24
             this.file = file;
 615  24
             this.depth = depth;
 616  24
         }
 617  
 
 618  
         /**
 619  
          * Return the file when the operation was cancelled.
 620  
          *
 621  
          * @return the file when the operation was cancelled
 622  
          */
 623  
         public File getFile() {
 624  12
             return file;
 625  
         }
 626  
 
 627  
         /**
 628  
          * Return the depth when the operation was cancelled.
 629  
          *
 630  
          * @return the depth when the operation was cancelled
 631  
          */
 632  
         public int getDepth() {
 633  16
             return depth;
 634  
         }
 635  
     }
 636  
 }