001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.io.monitor; 018 019import java.io.File; 020import java.io.Serializable; 021 022/** 023 * The state of a file or directory, capturing the following {@link File} attributes at a point in time. 024 * <ul> 025 * <li>File Name (see {@link File#getName()})</li> 026 * <li>Exists - whether the file exists or not (see {@link File#exists()})</li> 027 * <li>Directory - whether the file is a directory or not (see {@link File#isDirectory()})</li> 028 * <li>Last Modified Date/Time (see {@link File#lastModified()})</li> 029 * <li>Length (see {@link File#length()}) - directories treated as zero</li> 030 * <li>Children - contents of a directory (see {@link File#listFiles(java.io.FileFilter)})</li> 031 * </ul> 032 * 033 * <h2>Custom Implementations</h2> 034 * <p> 035 * If the state of additional {@link File} attributes is required then create a custom 036 * {@link FileEntry} with properties for those attributes. Override the 037 * {@link #newChildInstance(File)} to return a new instance of the appropriate type. 038 * You may also want to override the {@link #refresh(File)} method. 039 * </p> 040 * @see FileAlterationObserver 041 * @since 2.0 042 */ 043public class FileEntry implements Serializable { 044 045 private static final long serialVersionUID = -2505664948818681153L; 046 047 static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0]; 048 049 private final FileEntry parent; 050 private FileEntry[] children; 051 private final File file; 052 private String name; 053 private boolean exists; 054 private boolean directory; 055 private long lastModified; 056 private long length; 057 058 /** 059 * Construct a new monitor for a specified {@link File}. 060 * 061 * @param file The file being monitored 062 */ 063 public FileEntry(final File file) { 064 this(null, file); 065 } 066 067 /** 068 * Construct a new monitor for a specified {@link File}. 069 * 070 * @param parent The parent 071 * @param file The file being monitored 072 */ 073 public FileEntry(final FileEntry parent, final File file) { 074 if (file == null) { 075 throw new IllegalArgumentException("File is missing"); 076 } 077 this.file = file; 078 this.parent = parent; 079 this.name = file.getName(); 080 } 081 082 /** 083 * Refresh the attributes from the {@link File}, indicating 084 * whether the file has changed. 085 * <p> 086 * This implementation refreshes the <code>name</code>, <code>exists</code>, 087 * <code>directory</code>, <code>lastModified</code> and <code>length</code> 088 * properties. 089 * <p> 090 * The <code>exists</code>, <code>directory</code>, <code>lastModified</code> 091 * and <code>length</code> properties are compared for changes 092 * 093 * @param file the file instance to compare to 094 * @return {@code true} if the file has changed, otherwise {@code false} 095 */ 096 public boolean refresh(final File file) { 097 098 // cache original values 099 final boolean origExists = exists; 100 final long origLastModified = lastModified; 101 final boolean origDirectory = directory; 102 final long origLength = length; 103 104 // refresh the values 105 name = file.getName(); 106 exists = file.exists(); 107 directory = exists && file.isDirectory(); 108 lastModified = exists ? file.lastModified() : 0; 109 length = exists && !directory ? file.length() : 0; 110 111 // Return if there are changes 112 return exists != origExists || 113 lastModified != origLastModified || 114 directory != origDirectory || 115 length != origLength; 116 } 117 118 /** 119 * Create a new child instance. 120 * <p> 121 * Custom implementations should override this method to return 122 * a new instance of the appropriate type. 123 * 124 * @param file The child file 125 * @return a new child instance 126 */ 127 public FileEntry newChildInstance(final File file) { 128 return new FileEntry(this, file); 129 } 130 131 /** 132 * Return the parent entry. 133 * 134 * @return the parent entry 135 */ 136 public FileEntry getParent() { 137 return parent; 138 } 139 140 /** 141 * Return the level 142 * 143 * @return the level 144 */ 145 public int getLevel() { 146 return parent == null ? 0 : parent.getLevel() + 1; 147 } 148 149 /** 150 * Return the directory's files. 151 * 152 * @return This directory's files or an empty 153 * array if the file is not a directory or the 154 * directory is empty 155 */ 156 public FileEntry[] getChildren() { 157 return children != null ? children : EMPTY_ENTRIES; 158 } 159 160 /** 161 * Set the directory's files. 162 * 163 * @param children This directory's files, may be null 164 */ 165 public void setChildren(final FileEntry... children) { 166 this.children = children; 167 } 168 169 /** 170 * Return the file being monitored. 171 * 172 * @return the file being monitored 173 */ 174 public File getFile() { 175 return file; 176 } 177 178 /** 179 * Return the file name. 180 * 181 * @return the file name 182 */ 183 public String getName() { 184 return name; 185 } 186 187 /** 188 * Set the file name. 189 * 190 * @param name the file name 191 */ 192 public void setName(final String name) { 193 this.name = name; 194 } 195 196 /** 197 * Return the last modified time from the last time it 198 * was checked. 199 * 200 * @return the last modified time 201 */ 202 public long getLastModified() { 203 return lastModified; 204 } 205 206 /** 207 * Return the last modified time from the last time it 208 * was checked. 209 * 210 * @param lastModified The last modified time 211 */ 212 public void setLastModified(final long lastModified) { 213 this.lastModified = lastModified; 214 } 215 216 /** 217 * Return the length. 218 * 219 * @return the length 220 */ 221 public long getLength() { 222 return length; 223 } 224 225 /** 226 * Set the length. 227 * 228 * @param length the length 229 */ 230 public void setLength(final long length) { 231 this.length = length; 232 } 233 234 /** 235 * Indicate whether the file existed the last time it 236 * was checked. 237 * 238 * @return whether the file existed 239 */ 240 public boolean isExists() { 241 return exists; 242 } 243 244 /** 245 * Set whether the file existed the last time it 246 * was checked. 247 * 248 * @param exists whether the file exists or not 249 */ 250 public void setExists(final boolean exists) { 251 this.exists = exists; 252 } 253 254 /** 255 * Indicate whether the file is a directory or not. 256 * 257 * @return whether the file is a directory or not 258 */ 259 public boolean isDirectory() { 260 return directory; 261 } 262 263 /** 264 * Set whether the file is a directory or not. 265 * 266 * @param directory whether the file is a directory or not 267 */ 268 public void setDirectory(final boolean directory) { 269 this.directory = directory; 270 } 271}