Coverage Report - net.sourceforge.pebble.domain.FileManager
 
Classes in this File Line Coverage Branch Coverage Complexity
FileManager
88%
128/145
90%
67/74
3.5
 
 1  
 /*
 2  
  * Copyright (c) 2003-2011, Simon Brown
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions are met:
 7  
  *
 8  
  *   - Redistributions of source code must retain the above copyright
 9  
  *     notice, this list of conditions and the following disclaimer.
 10  
  *
 11  
  *   - Redistributions in binary form must reproduce the above copyright
 12  
  *     notice, this list of conditions and the following disclaimer in
 13  
  *     the documentation and/or other materials provided with the
 14  
  *     distribution.
 15  
  *
 16  
  *   - Neither the name of Pebble nor the names of its contributors may
 17  
  *     be used to endorse or promote products derived from this software
 18  
  *     without specific prior written permission.
 19  
  *
 20  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 21  
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22  
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23  
  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 24  
  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 25  
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 26  
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 27  
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 28  
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 29  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 30  
  * POSSIBILITY OF SUCH DAMAGE.
 31  
  */
 32  
 package net.sourceforge.pebble.domain;
 33  
 
 34  
 import net.sourceforge.pebble.comparator.FileMetaDataComparator;
 35  
 import net.sourceforge.pebble.util.FileUtils;
 36  
 import net.sourceforge.pebble.PebbleContext;
 37  
 import org.apache.commons.io.IOUtils;
 38  
 
 39  
 import java.io.*;
 40  
 import java.util.*;
 41  
 
 42  
 /**
 43  
  * Encapsulates methods for managing and manipulating files under the
 44  
  * following locations:
 45  
  * <ul>
 46  
  * <li>${blog.dir}/images</li>
 47  
  * <li>${blog.dir}/files</li>
 48  
  * <li>${editableTheme}</li>
 49  
  * </ul>
 50  
  *
 51  
  * @author Simon Brown
 52  
  */
 53  
 public class FileManager {
 54  
 
 55  
   /** the type of files being managed */
 56  
   private String type;
 57  
 
 58  
   /** the root directory for the particular file type */
 59  
   private File root;
 60  
 
 61  
   /**
 62  
    * Creates a new instande for the specified blog and type.
 63  
    *
 64  
    * @param blog    the blog that this manager refers to
 65  
    * @param type    the type of files to manage
 66  
    */
 67  272
   public FileManager(Blog blog, String type) {
 68  272
     this.type = type;
 69  
 
 70  
     // which directory are we looking at?
 71  272
     if (type.equals(FileMetaData.BLOG_IMAGE)) {
 72  24
       this.root = new File(blog.getImagesDirectory());
 73  248
     } else if (type.equals(FileMetaData.THEME_FILE)) {
 74  16
       this.root = blog.getEditableTheme().getPathToLiveTheme();
 75  232
     } else if (type.equals(FileMetaData.BLOG_DATA)) {
 76  12
       this.root = new File(blog.getRoot());
 77  
     } else {
 78  220
       this.root = new File(blog.getFilesDirectory());
 79  
     }
 80  272
   }
 81  
 
 82  
   /**
 83  
    * Gets the root directory that this class is managing.
 84  
    *
 85  
    * @return  a File instance
 86  
    */
 87  
   public File getRootDirectory() {
 88  20
     return this.root;
 89  
   }
 90  
 
 91  
   /**
 92  
    * Gets meta data about a specific file or directory.
 93  
    *
 94  
    * @param path    the path of the file/directory
 95  
    * @return        a FileMetaData object
 96  
    */
 97  
   public FileMetaData getFileMetaData(String path) {
 98  948
     FileMetaData metaData = new FileMetaData(this, path);
 99  948
     metaData.setType(type);
 100  
 
 101  
     // is it a directory?
 102  948
     File file = getFile(metaData);
 103  948
     if (file.exists()) {
 104  896
       if (file.isDirectory()) {
 105  596
         metaData.setDirectory(true);
 106  
         try {
 107  596
           List files = getFiles(metaData, true);
 108  580
           long size = 0;
 109  580
           Iterator it = files.iterator();
 110  936
           while (it.hasNext()) {
 111  356
             size += ((FileMetaData)it.next()).getSize();
 112  
           }
 113  580
           metaData.setSize(size);
 114  16
         } catch (IllegalFileAccessException ifae) {
 115  
           // do nothing
 116  596
         }
 117  
       } else {
 118  300
         metaData.setSize(file.length());
 119  
       }
 120  
 
 121  896
       metaData.setLastModified(new Date(file.lastModified()));
 122  
     }
 123  
 
 124  948
     return metaData;
 125  
   }
 126  
 
 127  
   public FileMetaData getParent(FileMetaData file) {
 128  32
     if (file.getAbsolutePath().equals("/")) {
 129  24
       return null;
 130  
     } else {
 131  8
       return getFileMetaData(file.getPath());
 132  
     }
 133  
   }
 134  
 
 135  
   /**
 136  
    * Gets meta data about a specific file or directory.
 137  
    *
 138  
    * @param path    the path of the file/directory
 139  
    * @param name    the name of the file/directory
 140  
    * @return        a FileMetaData object
 141  
    */
 142  
   public FileMetaData getFileMetaData(String path, String name) {
 143  456
     if (path != null && path.endsWith("/")) {
 144  412
       return getFileMetaData(path + name);
 145  
     } else {
 146  44
       return getFileMetaData(path + "/" + name);
 147  
     }
 148  
   }
 149  
 
 150  
   /**
 151  
    * Gets a java.io.File reference to the specified path, regardless
 152  
    * of whether it represents a file or directory.
 153  
    *
 154  
    * @param path    an absolute path from the root
 155  
    * @return    a java.io.File instance
 156  
    */
 157  
   public File getFile(String path) {
 158  
     String relativePath;
 159  40
     if (path != null && path.startsWith("/")) {
 160  24
       relativePath = path.substring(1);
 161  
     } else {
 162  16
       relativePath = path;
 163  
     }
 164  
 
 165  40
     return new File(root, relativePath);
 166  
   }
 167  
 
 168  
   /**
 169  
    * Convenience method to get a java.io.File reference to the file represented
 170  
    * by the specified FileMetaData object.
 171  
    *
 172  
    * @param file    the FileMetaData object representing the path
 173  
    * @return    a java.io.File instance
 174  
    */
 175  
   private File getFile(FileMetaData file) {
 176  1980
     String relativePath = file.getAbsolutePath().substring(1);
 177  1980
     return new File(root, relativePath);
 178  
   }
 179  
 
 180  
   /**
 181  
    * Determines whether the specified file is underneath the root directory
 182  
    * for this file manager.
 183  
    *
 184  
    * @param file    the java.io.File to test
 185  
    * @return    true if the file is underneath the root, false otherwise
 186  
    */
 187  
   public boolean isUnderneathRootDirectory(File file) {
 188  1028
     return FileUtils.underneathRoot(root, file);
 189  
   }
 190  
 
 191  
   /**
 192  
    * Creates a new directory with the specified name underneath the given path.
 193  
    *
 194  
    * @param path    the path under which to create the directory
 195  
    * @param name    the name of the directory
 196  
    * @return    a java.io.File instance representing the new directory
 197  
    */
 198  
   public File createDirectory(String path, String name) throws IllegalFileAccessException {
 199  36
     FileMetaData subDirectory = getFileMetaData(path);
 200  
 
 201  36
     File newDirectory = new File(getFile(subDirectory), name);
 202  36
     if (!isUnderneathRootDirectory(newDirectory)) {
 203  8
       throw new IllegalFileAccessException();
 204  
     } else {
 205  28
       newDirectory.mkdirs();
 206  
     }
 207  
 
 208  28
     return newDirectory;
 209  
   }
 210  
 
 211  
   /**
 212  
    * Copies a file.
 213  
    *
 214  
    * @param path      the path under which the file exists
 215  
    * @param name      the name of the file
 216  
    * @param newName   the new name of the file
 217  
    * @return    a java.io.File instance representing the new file, or null
 218  
    *            if the file isn't copied because no new name was given, or the
 219  
    *            new name is the same as the old name
 220  
    */
 221  
   public File copyFile(String path, String name, String newName) throws IOException, IllegalFileAccessException {
 222  32
     if (newName != null && newName.length() > 0 && !newName.equals(name)) {
 223  20
       FileMetaData subDirectory = getFileMetaData(path);
 224  20
       File originalFile = new File(getFile(subDirectory), name);
 225  20
       File newFile = new File(getFile(subDirectory), newName);
 226  
 
 227  20
       if (!isUnderneathRootDirectory(originalFile) || !isUnderneathRootDirectory(newFile)) {
 228  12
         throw new IllegalFileAccessException();
 229  
       }
 230  
 
 231  8
       FileUtils.copyFile(originalFile, newFile);
 232  
 
 233  8
       return newFile;
 234  
     } else {
 235  12
       return null;
 236  
     }
 237  
   }
 238  
 
 239  
   /**
 240  
    * Renames a file.
 241  
    *
 242  
    * @param path      the path under which the file exists
 243  
    * @param name      the name of the file
 244  
    * @param newName   the new name of the file
 245  
    * @return    a java.io.File instance representing the new file, or null
 246  
    *            if the file isn't copied because no new name was given, or the
 247  
    *            new name is the same as the old name
 248  
    */
 249  
   public File renameFile(String path, String name, String newName) throws IllegalFileAccessException {
 250  28
     if (newName != null && newName.length() > 0 && !newName.equals(name)) {
 251  16
       FileMetaData subDirectory = getFileMetaData(path);
 252  16
       File originalFile = new File(getFile(subDirectory), name);
 253  16
       File newFile = new File(getFile(subDirectory), newName);
 254  
 
 255  
       // check that newFile is underneath the root directory
 256  16
       if (!isUnderneathRootDirectory(originalFile) || !isUnderneathRootDirectory(newFile)) {
 257  8
         throw new IllegalFileAccessException();
 258  
       }
 259  
 
 260  8
       originalFile.renameTo(newFile);
 261  8
       return newFile;
 262  
     } else {
 263  12
       return null;
 264  
     }
 265  
   }
 266  
 
 267  
   /**
 268  
    * Deletes a file.
 269  
    *
 270  
    * @param path      the path under which the file exists
 271  
    * @param name      the name of the file
 272  
    */
 273  
   public void deleteFile(String path, String name) throws IllegalFileAccessException {
 274  76
     FileMetaData subDirectory = getFileMetaData(path);
 275  76
     File fileToDelete = new File(getFile(subDirectory), name);
 276  
 
 277  76
     if (!isUnderneathRootDirectory(fileToDelete)) {
 278  8
       throw new IllegalFileAccessException();
 279  
     }
 280  
 
 281  68
     FileUtils.deleteFile(fileToDelete);
 282  68
   }
 283  
 
 284  
   /**
 285  
    * Loads a file into a String.
 286  
    *
 287  
    * @param path      the path under which the file exists
 288  
    * @param name      the name of the file
 289  
    * @return  a String containing the content of the specified file
 290  
    */
 291  
   public String loadFile(String path, String name) throws IllegalFileAccessException {
 292  24
     StringBuffer content = new StringBuffer();
 293  
 
 294  24
     FileMetaData subDirectory = getFileMetaData(path);
 295  24
     File fileToLoad = new File(getFile(subDirectory), name);
 296  
 
 297  24
     if (!isUnderneathRootDirectory(fileToLoad)) {
 298  8
       throw new IllegalFileAccessException();
 299  
     }
 300  
 
 301  16
     BufferedReader reader = null;
 302  
     try {
 303  16
       reader = new BufferedReader(new FileReader(fileToLoad));
 304  16
       String line = reader.readLine();
 305  40
       while (line != null) {
 306  24
         content.append(line);
 307  
 
 308  24
         line = reader.readLine();
 309  24
         if (line != null) {
 310  8
           content.append(System.getProperty("line.separator"));
 311  
         }
 312  
       }
 313  0
     } catch (IOException ioe) {
 314  0
       ioe.printStackTrace();
 315  
     } finally {
 316  16
       IOUtils.closeQuietly(reader);
 317  16
     }
 318  
 
 319  16
     return content.toString();
 320  
   }
 321  
 
 322  
   /**
 323  
    * Saves a file with the given content.
 324  
    *
 325  
    * @param path      the path under which the file exists
 326  
    * @param name      the name of the file
 327  
    * @param content   the content as a String
 328  
    */
 329  
   public void saveFile(String path, String name, String content) throws IOException, IllegalFileAccessException {
 330  56
     FileMetaData subDirectory = getFileMetaData(path);
 331  56
     File fileToSave = new File(getFile(subDirectory), name);
 332  
 
 333  56
     if (!isUnderneathRootDirectory(fileToSave)) {
 334  8
       throw new IllegalFileAccessException();
 335  
     }
 336  
 
 337  48
     BufferedWriter writer = null;
 338  
     try {
 339  48
       writer = new BufferedWriter(new FileWriter(fileToSave));
 340  48
       writer.write(content);
 341  48
       writer.flush();
 342  
     } finally {
 343  48
       IOUtils.closeQuietly(writer);
 344  48
     }
 345  48
   }
 346  
 
 347  
   /**
 348  
    * Saves a file with the given binary content.
 349  
    *
 350  
    * @param name      the name of the file
 351  
    * @param content   the binary content
 352  
    * @return  a FileMetaData instance representing the saved file
 353  
    */
 354  
   public FileMetaData saveFile(String name, byte[] content) throws IOException, IllegalFileAccessException {
 355  0
     FileMetaData file = getFileMetaData(name);
 356  0
     File fileToSave = getFile(name);
 357  
 
 358  0
     if (!isUnderneathRootDirectory(fileToSave)) {
 359  0
       throw new IllegalFileAccessException();
 360  
     }
 361  
 
 362  0
     BufferedOutputStream out = null;
 363  
     try {
 364  0
       out = new BufferedOutputStream(new FileOutputStream(fileToSave));
 365  0
       out.write(content);
 366  0
       out.flush();
 367  
     } finally {
 368  0
       IOUtils.closeQuietly(out);
 369  0
     }
 370  
 
 371  0
     return file;
 372  
   }
 373  
 
 374  
   /**
 375  
    * Gets a list of files that reside under a given path.
 376  
    *
 377  
    * @param path      the path under which the file exists
 378  
    * @return  a List of FileMetaData instances
 379  
    * @throws IllegalFileAccessException   if trying to access a file outside the root
 380  
    */
 381  
   public List getFiles(String path) throws IllegalFileAccessException {
 382  56
     return getFiles(path, false);
 383  
   }
 384  
 
 385  
   public List getFiles(String path, boolean includeChildren) throws IllegalFileAccessException {
 386  172
     FileMetaData subDirectory = getFileMetaData(path);
 387  172
     return getFiles(subDirectory, includeChildren);
 388  
   }
 389  
 
 390  
   private List getFiles(FileMetaData path, boolean includeChildren) throws IllegalFileAccessException {
 391  768
     File directoryToView = getFile(path);
 392  
 
 393  768
     if (!isUnderneathRootDirectory(directoryToView)) {
 394  24
       throw new IllegalFileAccessException();
 395  
     }
 396  
 
 397  744
     List directoriesAndFiles = new ArrayList();
 398  744
     List files = new ArrayList();
 399  744
     List directories = new ArrayList();
 400  744
     File f[] = directoryToView.listFiles();
 401  744
     if (f != null) {
 402  
       File file;
 403  1156
       for (int i = 0; i < f.length; i++) {
 404  420
         file = f[i];
 405  420
         if (file.isDirectory()) {
 406  128
           FileMetaData metaData = getFileMetaData(path.getAbsolutePath(), file.getName());
 407  128
           directories.add(metaData);
 408  
 
 409  128
           if (includeChildren) {
 410  112
             directories.addAll(getFiles(metaData.getAbsolutePath(), true));
 411  
           } else {
 412  16
             Collections.sort(directories, new FileMetaDataComparator());
 413  
           }
 414  
         }
 415  
       }
 416  
 
 417  1156
       for (int i = 0; i < f.length; i++) {
 418  420
         file = f[i];
 419  420
         if (file.isFile()) {
 420  292
           FileMetaData metaData = getFileMetaData(path.getAbsolutePath(), file.getName());
 421  292
           files.add(metaData);
 422  
         }
 423  
       }
 424  
 
 425  736
       Collections.sort(files, new FileMetaDataComparator());
 426  
     }
 427  
 
 428  744
     directoriesAndFiles.addAll(directories);
 429  744
     directoriesAndFiles.addAll(files);
 430  
 
 431  744
     return directoriesAndFiles;
 432  
   }
 433  
 
 434  
   /**
 435  
    * Determines how much space is being used in files, images and theme.
 436  
    *
 437  
    * @param blog    the blog to check against
 438  
    * @return  the number of KB
 439  
    */
 440  
   public static double getCurrentUsage(Blog blog) {
 441  0
     FileManager imagesFileManager = new FileManager(blog, FileMetaData.BLOG_IMAGE);
 442  0
     FileManager filesFileManager = new FileManager(blog, FileMetaData.BLOG_FILE);
 443  0
     FileManager themeFileManager = new FileManager(blog, FileMetaData.THEME_FILE);
 444  0
     return  imagesFileManager.getFileMetaData("/").getSizeInKB() +
 445  
             filesFileManager.getFileMetaData("/").getSizeInKB() +
 446  
             themeFileManager.getFileMetaData("/").getSizeInKB();
 447  
   }
 448  
 
 449  
 
 450  
   /**
 451  
    * Determines whether there is enough space to store the given number of KB.
 452  
    *
 453  
    * @param blog    the blog to check against
 454  
    * @param itemSize  the size of the item to be written
 455  
    * @return  true if there is enough space or quotas aren't active
 456  
    */
 457  
   public static boolean hasEnoughSpace(Blog blog, double itemSize) {
 458  8
     long quota = PebbleContext.getInstance().getConfiguration().getFileUploadQuota();
 459  
 
 460  8
     return (quota == -1) || ((quota - getCurrentUsage(blog)) > itemSize);
 461  
   }
 462  
 
 463  
 }