Coverage Report - org.apache.creadur.whisker.scan.FromFileSystem
 
Classes in this File Line Coverage Branch Coverage Complexity
FromFileSystem
0%
0/3
N/A
2.333
FromFileSystem$Builder
0%
0/26
0%
0/8
2.333
FromFileSystem$Builder$Work
0%
0/56
0%
0/38
2.333
 
 1  
 /**
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  *  to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  *  with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License. 
 18  
  */
 19  
 package org.apache.creadur.whisker.scan;
 20  
 
 21  
 import java.io.File;
 22  
 import java.io.IOException;
 23  
 import java.util.ArrayList;
 24  
 import java.util.Collection;
 25  
 import java.util.LinkedList;
 26  
 import java.util.Queue;
 27  
 import java.util.Set;
 28  
 import java.util.TreeSet;
 29  
 
 30  
 /**
 31  
  * Scans directories for resources, within a file system.
 32  
  */
 33  
 public class FromFileSystem {
 34  
     
 35  
     /**
 36  
      * Base constructor.
 37  
      */
 38  
     public FromFileSystem() {
 39  0
         super();
 40  0
     }
 41  
 
 42  
     /**
 43  
      * Builds 
 44  
      * @param base names the base directory, not null
 45  
      * @return collected directories within the base, not null
 46  
      * @throws IOException when the scanning fails
 47  
      */
 48  
     public Collection<Directory> withBase(final String base) throws IOException {
 49  0
         return new Builder(base).build();
 50  
     }
 51  
     
 52  
     private final static class Builder {
 53  
         /** Initial capacity for the backing array. */
 54  
         private static final int DEFAULT_INITIAL_CAPACITY = 64;
 55  
         /** Directory scanning base. */
 56  
         private final File base;
 57  
         /** Directories scanned. */
 58  
         private final Set<Directory> directories;
 59  
         /** Queues work not yet complete. */
 60  
         private final Queue<Work> workInProgress;
 61  
         /** Stores work done. */
 62  
         private final Collection<Work> workDone;
 63  
         
 64  
         /**
 65  
          * Constructs a builder with given base 
 66  
          * (and default backing array).
 67  
          * @param base not null
 68  
          */
 69  
         public Builder(final String base) {
 70  0
             this(base, DEFAULT_INITIAL_CAPACITY);
 71  0
         }
 72  
 
 73  
         /**
 74  
          * Constructs a builder.
 75  
          * @param base not null
 76  
          * @param initialCapacity initial capacity for backing array
 77  
          */
 78  
         public Builder(final String base, final int initialCapacity) {
 79  0
             super();
 80  0
             this.base = new File(base);
 81  0
             directories = new TreeSet<Directory>();
 82  0
             workInProgress = new LinkedList<Work>();
 83  0
             workDone = new ArrayList<Work>(initialCapacity);
 84  0
         }
 85  
         
 86  
         /**
 87  
          * Builds directories.
 88  
          * @return not null
 89  
          * @throws IOException when scanning fails
 90  
          */
 91  
         public Collection<Directory> build() throws IOException {
 92  0
             put(base).andWork().untilDone();
 93  0
             return directories;
 94  
         }
 95  
 
 96  
         /**
 97  
          * Waiting until work done.
 98  
          */
 99  0
         private void untilDone() { }
 100  
 
 101  
         /**
 102  
          * Adds file work to the queue.
 103  
          * @param file not null
 104  
          * @return this, not null
 105  
          */
 106  
         private Builder put(final File file) {
 107  0
             return put(new Work(file));
 108  
         }
 109  
         
 110  
         /**
 111  
          * Queues work.
 112  
          * @param work not null
 113  
          * @return this, not null
 114  
          */
 115  
         private Builder put(final Work work) {
 116  0
             if (work != null) {
 117  0
                 if (workDone.contains(work)) {
 118  0
                     alreadyDone(work);
 119  
                 } else {
 120  0
                     this.workInProgress.add(work);
 121  
                 }
 122  
             }
 123  0
             return this;
 124  
         }
 125  
         
 126  
         /**
 127  
          * Notes that work has already been done.
 128  
          * @param work not null
 129  
          */
 130  
         private void alreadyDone(final Work work) {
 131  0
             System.out.println("Already done " + work);
 132  0
         }
 133  
 
 134  
         /**
 135  
          * Starts work.
 136  
          * @return this, not null
 137  
          */
 138  
         private Builder andWork() {
 139  0
             while (!workInProgress.isEmpty()) {
 140  0
                 workDone.add(workOn(workInProgress.poll()));
 141  
             }
 142  0
             return this;
 143  
         }
 144  
 
 145  
         /**
 146  
          * Performs work.
 147  
          * @param next not null
 148  
          * @return the work done, not null
 149  
          */
 150  
         private Work workOn(final Work next) {
 151  0
             for (final String name: next.contents()) {
 152  0
                 put(next.whenDirectory(name));
 153  
             }
 154  0
             directories.add(next.build());
 155  0
             return next;
 156  
         }
 157  
         
 158  
         /**
 159  
          * Computes the contents of a directory.
 160  
          */
 161  
         private final static class Work {
 162  
             /** Represents base directory. */
 163  
             private static final String BASE_DIRECTORY = ".";
 164  
             /** Names the directory. */
 165  
             private final String name;
 166  
             /** The directory worked on. */
 167  
             private final File file;
 168  
             
 169  
             public Work(File file) {
 170  0
                 this(BASE_DIRECTORY, file);
 171  0
             }
 172  
 
 173  
             /**
 174  
              * Constructs work.
 175  
              * @param name not null
 176  
              * @param file not null
 177  
              */
 178  0
             public Work(final String name, final File file) {
 179  0
                 if (! file.exists()) {
 180  0
                     throw new IllegalArgumentException(
 181  
                             "Expected '"+ file.getAbsolutePath() + "' to exist");
 182  
                 }
 183  0
                 if (! file.isDirectory()) {
 184  0
                     throw new IllegalArgumentException(
 185  
                             "Expected '"+ file.getAbsolutePath() + "' to be a directory");
 186  
                 }
 187  0
                 this.name = name;
 188  0
                 this.file = file;
 189  0
             }
 190  
 
 191  
             /**
 192  
              * Gets the contents of the work directory.
 193  
              * @return not null
 194  
              */
 195  
             public String[] contents() {
 196  0
                 final String[] contents = file.list();
 197  0
                 if (contents == null) {
 198  0
                     throw new IllegalArgumentException("Cannot list content of " + file);
 199  
                 }
 200  0
                 return contents;
 201  
             }
 202  
 
 203  
             /**
 204  
              * Builds a directory.
 205  
              * @return not null
 206  
              */
 207  
             public Directory build() {
 208  0
                 final Directory result = new Directory().setName(name);
 209  0
                 for (final String name : contents()) {
 210  0
                     if (isResource(name)) {
 211  0
                         result.addResource(name);
 212  
                     }
 213  
                 }
 214  0
                 return result;
 215  
             }
 216  
 
 217  
             /**
 218  
              * Is the named file a resource?
 219  
              * @param name not null
 220  
              * @return true when the named file is a resource,
 221  
              * false otherwise
 222  
              */
 223  
             private boolean isResource(final String name) {
 224  0
                 return !isDirectory(name);
 225  
             }
 226  
 
 227  
             /**
 228  
              * Is the named file a directory?
 229  
              * @param name not null
 230  
              * @return true when the named file is a directory,
 231  
              * false otherwise
 232  
              */
 233  
             private boolean isDirectory(final String name) {
 234  0
                 return file(name).isDirectory();
 235  
             }
 236  
 
 237  
             /**
 238  
              * Creates new work.
 239  
              * @param name not null
 240  
              * @return work for the named directory,
 241  
              * or null when the resource named is not a directory
 242  
              */
 243  
             public Work whenDirectory(final String name) {
 244  0
                 final File file = file(name);
 245  
                 final Work result;
 246  0
                 if (file.isDirectory()) {
 247  0
                     result = new Work(path(name), file);
 248  
                 } else {
 249  0
                     result = null;
 250  
                 }
 251  0
                 return result;
 252  
             }
 253  
 
 254  
             /**
 255  
              * Converts a name to a path relative to base.
 256  
              * @param name not null
 257  
              * @return not null
 258  
              */
 259  
             private String path(final String name) {
 260  
                 final String result;
 261  0
                 if (isBaseDirectory()) {
 262  0
                     result = name;
 263  
                 } else {
 264  0
                     result = this.name + "/" + name;
 265  
                 }
 266  0
                 return result;
 267  
             }
 268  
 
 269  
             /**
 270  
              * This the work done in the base directory.
 271  
              * @return true when this is the base, false otherwise.
 272  
              */
 273  
             private boolean isBaseDirectory() {
 274  0
                 return BASE_DIRECTORY.equals(this.name);
 275  
             }
 276  
 
 277  
             /**
 278  
              * Creates a file.
 279  
              * @param name not null
 280  
              * @return file with given name
 281  
              */
 282  
             private File file(String name) {
 283  0
                 return new File(this.file, name);
 284  
             }
 285  
 
 286  
             /**
 287  
              * Computes some suitable hash.
 288  
              * @return a hash code
 289  
              * @see java.lang.Object#hashCode()
 290  
              */
 291  
             @Override
 292  
             public int hashCode() {
 293  0
                 final int prime = 31;
 294  0
                 int result = 1;
 295  0
                 result = prime * result
 296  
                         + ((file == null) ? 0 : file.hashCode());
 297  0
                 result = prime * result
 298  
                         + ((name == null) ? 0 : name.hashCode());
 299  0
                 return result;
 300  
             }
 301  
             
 302  
             /**
 303  
              * Equal when both name and file are equal.
 304  
              * @param obj possibly null
 305  
              * @return true when equal, false otherwise
 306  
              * @see java.lang.Object#equals(java.lang.Object)
 307  
              */
 308  
             @Override
 309  
             public boolean equals(final Object obj) {
 310  0
                 if (this == obj) {
 311  0
                     return true;
 312  
                 }
 313  0
                 if (obj == null) {
 314  0
                     return false;
 315  
                 }
 316  0
                 if (getClass() != obj.getClass()) {
 317  0
                     return false;
 318  
                 }
 319  0
                 final Work other = (Work) obj;
 320  0
                 if (file == null) {
 321  0
                     if (other.file != null)
 322  0
                         return false;
 323  0
                 } else if (!file.equals(other.file))
 324  0
                     return false;
 325  0
                 if (name == null) {
 326  0
                     if (other.name != null) {
 327  0
                         return false;
 328  
                     }
 329  0
                 } else if (!name.equals(other.name)) {
 330  0
                     return false;
 331  
                 }
 332  0
                 return true;
 333  
             }
 334  
             
 335  
             /**
 336  
              * Something suitable for logging.
 337  
              * @return not null
 338  
              * @see java.lang.Object#toString()
 339  
              */
 340  
             @Override
 341  
             public String toString() {
 342  0
                 return "Work [name=" + name + ", file=" + file + "]";
 343  
             }
 344  
         }
 345  
     }
 346  
 }