Coverage Report - org.apache.commons.finder.FileFinder
 
Classes in this File Line Coverage Branch Coverage Complexity
FileFinder
49%
50/102
37%
22/60
4
 
 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.finder;
 18  
 
 19  
 import java.io.File;
 20  
 import java.util.ArrayList;
 21  
 import java.util.Collections;
 22  
 import java.util.Iterator;
 23  
 import java.util.List;
 24  
 import java.util.Map;
 25  
 
 26  
 /**
 27  
  * Searches for files that match certain criteria in a directory, and
 28  
  * typically also subdirectories.
 29  
  * <p>
 30  
  * This is a programmatic equivalent of the search functions present
 31  
  * in many operating systems. You can be informed dynamically of
 32  
  * events as they occur by adding a listener.
 33  
  * 
 34  
  * @author Henri Yandell
 35  
  * @version $Id: FileFinder.java 437543 2006-08-28 05:47:51Z bayard $
 36  
  * @since 1.1
 37  
  */
 38  
 public class FileFinder implements Finder {
 39  
 
 40  
     /** The list of listeners. */
 41  
     private List findListeners;
 42  
 
 43  
     /**
 44  
      * Constructor.
 45  
      */
 46  
     public FileFinder() {
 47  15
         super();
 48  15
     }
 49  
 
 50  
     //-----------------------------------------------------------------------
 51  
     /**
 52  
      * Find all files in the specified directory.
 53  
      * 
 54  
      * @param directory  the directory to search in
 55  
      */
 56  
     public File[] find(File directory) {
 57  0
         return find(directory, Collections.EMPTY_MAP);
 58  
     }
 59  
 
 60  
     /**
 61  
      * Finds files in the specified directory that match the given options.
 62  
      * 
 63  
      * @param directory  the directory to search in
 64  
      * @param options  the options to use
 65  
      */
 66  
     public File[] find(File directory, Map options) {
 67  15
         List retlist = new ArrayList();
 68  15
         find(directory, options, retlist);
 69  15
         File[] files = (File[]) retlist.toArray(new File[retlist.size()]);
 70  15
         return files;
 71  
     }
 72  
 
 73  
     /**
 74  
      * Finds files in the specified directory that match the given options.
 75  
      * The results are added to the non-null list provided.
 76  
      * <p>
 77  
      * Note: To avoid large memory allocations, avoid adding any FileListeners,
 78  
      * and try overwriding List.add(Object o) instead.
 79  
      * 
 80  
      * @param directory  the directory to search in
 81  
      * @param options  the options to use
 82  
      * @param foundFiles  a List to which all found files will be added
 83  
      */
 84  
     public void find(File directory, Map options, List foundFiles) {
 85  15
         if (foundFiles == null) {
 86  0
             throw new IllegalArgumentException("foundFiles list cannot be null");
 87  
         }
 88  
         
 89  15
         notifyDirectoryStarted(directory);
 90  15
         boolean depthFirst = toBoolean(options.get(Finder.DEPTH));
 91  15
         int maxDepth = toInt(options.get(Finder.MAXDEPTH));
 92  15
         int minDepth = toInt(options.get(Finder.MINDEPTH));
 93  15
         boolean ignoreHiddenDirs = toBoolean(options.get(Finder.IGNORE_HIDDEN_DIRS));
 94  
         
 95  15
         FindingFilter filter = new FindingFilter(options);
 96  15
         int startIdx = foundFiles.size();
 97  15
         find(directory, filter, depthFirst, foundFiles);
 98  15
         if (filter.accept(directory)) {
 99  3
             if (depthFirst) {
 100  0
                 foundFiles.add(directory);
 101  0
             } else {
 102  3
                 foundFiles.add(0, directory);
 103  
             }
 104  
         }
 105  15
         int endIdx = foundFiles.size();
 106  15
         notifyDirectoryFinished(directory, foundFiles, startIdx, endIdx);        
 107  15
     }
 108  
 
 109  
     private void find(File directory, FindingFilter filter, boolean depthFirst, List retlist) {
 110  
         // we can't use listFiles(filter) here, directories don't work correctly
 111  180
         File[] list = directory.listFiles();
 112  180
         if (list == null) {
 113  0
             return;
 114  
         }
 115  180
         int sz = list.length;
 116  468
         for (int i = 0; i < sz; i++) {
 117  288
             File tmp = list[i];
 118  288
             if (!depthFirst && filter.accept(tmp)) {
 119  17
                 retlist.add(tmp);
 120  17
                 notifyFileFound(directory, tmp);
 121  
             }
 122  288
             if (tmp.isDirectory()) {
 123  165
                 notifyDirectoryStarted(tmp);
 124  165
                 int startIdx = retlist.size();
 125  165
                 find(tmp, filter, depthFirst, retlist);
 126  165
                 int endIdx = retlist.size();
 127  165
                 notifyDirectoryFinished(tmp, retlist, startIdx, endIdx);
 128  
             }
 129  288
             if (depthFirst && filter.accept(tmp)) {
 130  0
                 retlist.add(tmp);
 131  0
                 notifyFileFound(directory, tmp);
 132  
             }
 133  
         }
 134  180
     }
 135  
 
 136  
     //-----------------------------------------------------------------------
 137  
     /**
 138  
      * Adds a FindListener that is notified when a file is found.
 139  
      * 
 140  
      * @param listener  the listener
 141  
      */
 142  
     public void addFindListener(FindListener listener) {
 143  0
         if (findListeners == null) {
 144  0
             findListeners = new ArrayList();
 145  
         }
 146  0
         findListeners.add(listener);
 147  0
     }
 148  
 
 149  
     /**
 150  
      * Removes a FindListener.
 151  
      * 
 152  
      * @param listener  the listener
 153  
      */
 154  
     public void removeFindListener(FindListener listener) {
 155  0
         if (findListeners != null) {
 156  0
             findListeners.remove(listener);
 157  
         }
 158  0
     }
 159  
 
 160  
     //-----------------------------------------------------------------------
 161  
     /**
 162  
      * Notify all FindListeners that a directory is being started.
 163  
      * 
 164  
      * @param directory  the directory
 165  
      */
 166  
     protected void notifyDirectoryStarted(File directory) {
 167  180
         if (!directory.isDirectory()) {
 168  0
             return;
 169  
         }
 170  180
         if (findListeners != null) {
 171  0
             FindEvent fe = new FindEvent(this, "directoryStarted", directory);
 172  0
             Iterator it = findListeners.iterator();
 173  0
             while (it.hasNext()) {
 174  0
                 FindListener findListener = (FindListener) it.next();
 175  0
                 findListener.directoryStarted(fe);
 176  0
             }
 177  
         }
 178  180
     }
 179  
 
 180  
     /**
 181  
      * Notify all FindListeners that a directory has been finished.
 182  
      * 
 183  
      * @param directory  the directory
 184  
      * @param files  the files that were found in the directory
 185  
      */
 186  
     protected void notifyDirectoryFinished(File directory, File[] files) {
 187  0
         if (!directory.isDirectory()) {
 188  0
             return;
 189  
         }
 190  0
         if (findListeners != null) {
 191  0
             FindEvent fe = new FindEvent(this, "directoryFinished", directory, files);
 192  0
             Iterator it = findListeners.iterator();
 193  0
             while (it.hasNext()) {
 194  0
                 FindListener findListener = (FindListener) it.next();
 195  0
                 findListener.directoryFinished(fe);
 196  0
             }
 197  
         }
 198  0
     }
 199  
 
 200  
     private void notifyDirectoryFinished(File directory, List files, int startIdx, int endIdx) {
 201  
         // only allocate a File array if we really have to 
 202  180
         if (!directory.isDirectory() || findListeners == null || findListeners.size() == 0) {
 203  180
             return;
 204  
         }
 205  
         
 206  
         // we should drop this when/if FindEvent stops dealing with File arrays
 207  0
         File[] filesa = (File[]) files.subList(startIdx, endIdx).toArray(new File[endIdx - startIdx]);
 208  0
         notifyDirectoryFinished(directory, filesa);
 209  
         
 210  0
     }
 211  
 
 212  
     /**
 213  
      * Notifies each FindListeners that a file has been found.
 214  
      * 
 215  
      * @param directory  the directory being processed
 216  
      * @param file  the file that was found
 217  
      */
 218  
     protected void notifyFileFound(File directory, File file) {
 219  17
         if (file.isDirectory()) {
 220  1
             return;
 221  
         }
 222  16
         if (findListeners != null) {
 223  0
             FindEvent fe = new FindEvent(this, "fileFound", directory, file);
 224  0
             Iterator it = findListeners.iterator();
 225  0
             while (it.hasNext()) {
 226  0
                 FindListener findListener = (FindListener) it.next();
 227  0
                 findListener.fileFound(fe);
 228  0
             }
 229  
         }
 230  16
     }
 231  
 
 232  
     //-----------------------------------------------------------------------
 233  
     /**
 234  
      * Converts an object to an int.
 235  
      * 
 236  
      * @param obj  the object
 237  
      * @return an int
 238  
      */
 239  
     private static int toInt(Object obj) {
 240  30
         if (obj == null) {
 241  30
             return 0;
 242  0
         } else if (obj instanceof Number) {
 243  0
             return ((Number) obj).intValue();
 244  
         } else {
 245  0
             String str = obj.toString();
 246  
             try {
 247  0
                 return Integer.parseInt(str.toString());
 248  0
             } catch(NumberFormatException nfe) {
 249  0
                 throw new IllegalArgumentException("String argument " + str + " must be parseable as an integer");
 250  
             }
 251  
         }
 252  
     }
 253  
 
 254  
     /**
 255  
      * Converts an object to a boolean.
 256  
      * 
 257  
      * @param obj  the object
 258  
      * @return a boolean
 259  
      */
 260  
     private static boolean toBoolean(Object obj) {
 261  30
         if (obj == null) {
 262  30
             return false;
 263  0
         } else if (obj instanceof Boolean) {
 264  0
             return ((Boolean) obj).booleanValue();
 265  0
         } else if (obj instanceof Number) {
 266  0
             return ((Number) obj).intValue() != 0;
 267  
         } else {
 268  0
             String str = obj.toString();
 269  0
             return new Boolean(str).booleanValue();
 270  
         }
 271  
     }
 272  
 
 273  
 }