001: /*--
002:
003: Copyright (C) 2000-2003 Anthony Eden.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The name "EdenLib" must not be used to endorse or promote products
019: derived from this software without prior written permission. For
020: written permission, please contact me@anthonyeden.com.
021:
022: 4. Products derived from this software may not be called "EdenLib", nor
023: may "EdenLib" appear in their name, without prior written permission
024: from Anthony Eden (me@anthonyeden.com).
025:
026: In addition, I request (but do not require) that you include in the
027: end-user documentation provided with the redistribution and/or in the
028: software itself an acknowledgement equivalent to the following:
029: "This product includes software developed by
030: Anthony Eden (http://www.anthonyeden.com/)."
031:
032: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
033: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
034: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
035: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
036: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
037: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
038: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
039: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
040: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
041: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
042: POSSIBILITY OF SUCH DAMAGE.
043:
044: For more information on EdenLib, please see <http://edenlib.sf.net/>.
045:
046: */
047:
048: package com.anthonyeden.lib.util;
049:
050: import org.apache.commons.vfs.FileObject;
051: import org.apache.commons.vfs.FileContent;
052: import org.apache.commons.vfs.FileSystemException;
053:
054: import org.apache.commons.logging.Log;
055: import org.apache.commons.logging.LogFactory;
056:
057: import com.anthonyeden.lib.Reloadable;
058: import com.anthonyeden.lib.ChainedRuntimeException;
059:
060: /** Class which monitors a file in a thread separate from the main application.
061: If the file changes then the reload() method of the given target will be
062: executed.
063:
064: @author Anthony Eden
065: */
066:
067: public class VFSFileMonitor implements Runnable {
068:
069: /** The default delay value (5 seconds) for checking for modifications. */
070: public static final int DEFAULT_DELAY = 5000;
071:
072: private static final Log log = LogFactory
073: .getLog(VFSFileMonitor.class);
074:
075: private FileObject file;
076: private long delay;
077: private Reloadable target;
078: private long lastModified;
079:
080: private Thread thread;
081: private boolean running = false;
082:
083: /** Construct a new VFSFileMonitor for the given file and target. The
084: default delay time will be used.
085:
086: @param file The file to monitor
087: @param target The target
088: @throws FileSystemException
089: */
090:
091: public VFSFileMonitor(FileObject file, Reloadable target)
092: throws FileSystemException {
093: this (file, DEFAULT_DELAY, target);
094: }
095:
096: /** Construct a new VFSFileMonitor for the given file and target. The given
097: delay time will be used.
098:
099: @param file The file to monitor
100: @param delay The delay time
101: @param target The target
102: @throws FileSystemException
103: */
104:
105: public VFSFileMonitor(FileObject file, long delay, Reloadable target)
106: throws FileSystemException {
107: this .file = file;
108: this .delay = delay;
109: this .target = target;
110:
111: lastModified = file.getContent().getLastModifiedTime();
112: }
113:
114: /** Start the monitoring thread. If the thread is already running then
115: this method will not attempt to start a new thread.
116: */
117:
118: public void startMonitor() {
119: if (!running) {
120: log.debug("Starting FileMonitor");
121:
122: running = true;
123: thread = new Thread(this );
124: thread.setDaemon(true);
125: thread.start();
126: }
127: }
128:
129: /** Stop the monitoring thread. If the monitoring thread is not running
130: then this method will do nothing.
131: */
132:
133: public void stopMonitor() {
134: if (thread != null && running) {
135: log.debug("Stopping FileMonitor");
136:
137: running = false;
138: thread.interrupt();
139: }
140: }
141:
142: /** Get the file which is being monitored.
143:
144: @return The monitored file
145: */
146:
147: public FileObject getFile() {
148: return file;
149: }
150:
151: /** Get the delay between file checks.
152:
153: @return The delay in milliseconds
154: */
155:
156: public long getDelay() {
157: return delay;
158: }
159:
160: /** Set the delay between checks. If the thread is already sleeping then
161: this delay will take effect during the next sleep.
162:
163: @param delay The delay in milliseconds
164: */
165:
166: public void setDelay(long delay) {
167: this .delay = delay;
168: }
169:
170: /** The thread's run method. This method should not be executed directly
171: nor should a thread be manually created, rather the <code>startMonitor()</code>
172: and <code>stopMonitor()</code> methods should be used to start and stop
173: the monitor.
174: */
175:
176: public void run() {
177: log.debug("FileMonitor running.");
178: while (running) {
179: try {
180: Thread.sleep(delay);
181: } catch (InterruptedException e) {
182: // do nothing
183: }
184:
185: try {
186: FileContent content = file.getContent();
187: long currentLastModified = content
188: .getLastModifiedTime();
189: if (currentLastModified != lastModified) {
190: log.info("Reloading " + file);
191: target.reload();
192: lastModified = currentLastModified;
193: }
194: } catch (FileSystemException e) {
195: throw new ChainedRuntimeException(e);
196: }
197: }
198: log.debug("FileMonitor stopped.");
199: }
200:
201: }
|