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