001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049:
050: package org.jaffa.cache;
051:
052: import org.apache.log4j.Logger;
053: import java.util.*;
054: import java.io.File;
055:
056: /** This is a helper class to monitor file(s), which provide data to a cache. The cache will be cleared, whenever any of the source files are modified. <B>Note that any open iterators on the cache will have unpredictable results, whenever the cache is flushed.</B>
057: * Create an instance of this class, providing the cache and the file(s) to be monitored. Then invoke the startMonitoring method. This will create a daemon Thread, which will monitor the files for any changes. Invoke the stopMonitoring method to stop the thread.
058: * @author GautamJ
059: */
060: public class CacheSourceMonitor {
061:
062: private static final Logger log = Logger
063: .getLogger(CacheSourceMonitor.class);
064:
065: // Default monitor frequency (5 minutes) in milliseconds.
066: private static final long DEFAULT_FREQUENCY = 5 * 60 * 1000;
067:
068: private ICache m_cache = null;
069: private Collection m_files = new LinkedList();
070: private Thread m_thread = null;
071: private boolean m_executeThread = false;
072: private long m_millis = 0;
073:
074: /** Creates a new instance of CacheSourceMonitor.
075: * @param cache The cache to be cleared, if any of the source files are modified.
076: */
077: public CacheSourceMonitor(ICache cache) {
078: this (cache, null);
079: }
080:
081: /** Creates a new instance of CacheSourceMonitor.
082: * @param cache The cache to be cleared, if any of the source files are modified.
083: * @param file The file to be monitored. In case, the input represents a directory, then all the files (one level deep) under that directory will be monitored for any changes.
084: */
085: public CacheSourceMonitor(ICache cache, String file) {
086: m_cache = cache;
087: if (file != null)
088: m_files.add(file);
089: }
090:
091: /** Add a file to be monitored for changes. In case, the input represents a directory, then all the files (one level deep) under that directory will be monitored for any changes.
092: * @param file The file to be monitored. In case, the input represents a directory, then all the files (one level deep) under that directory will be monitored for any changes.
093: */
094: public void addFile(String file) {
095: m_files.add(file);
096: }
097:
098: /** This will create a daemon Thread for monitoring the files. This thread will be run at the lowest priority, every 5 minutes by default.
099: */
100: public void startMonitoring() {
101: startMonitoring(0);
102: }
103:
104: /** This will create a daemon Thread for monitoring the files. This thread will be run at the lowest priority at the input frequency.
105: * @param minutes The frequency at which the files will be monitored.
106: */
107: public void startMonitoring(int minutes) {
108: m_millis = minutes > 0 ? minutes * 60 * 1000
109: : DEFAULT_FREQUENCY;
110: if (m_thread == null) {
111: m_thread = new CacheSourceMonitorThread();
112: m_thread.setDaemon(true);
113: }
114: m_executeThread = true;
115: m_thread.start();
116: }
117:
118: /** This will stop the Thread, that was created by the call to the startMonitoring method. */
119: public void stopMonitoring() {
120: m_executeThread = false;
121: if (m_thread != null)
122: m_thread.interrupt();
123: }
124:
125: /** This will monitor the files.
126: */
127: private void monitor() {
128: long time = System.currentTimeMillis() - m_millis;
129: for (Iterator itr = m_files.iterator(); itr.hasNext();) {
130: String fileName = (String) itr.next();
131: File file = new File(fileName);
132: if (!file.exists())
133: continue;
134:
135: if (file.isFile()) {
136: if (file.lastModified() > time) {
137: if (log.isDebugEnabled())
138: log
139: .debug(fileName
140: + " has been modified. The Cache will be flushed.");
141: m_cache.clear();
142: break;
143: }
144: } else if (file.isDirectory()) {
145: // Just monitor the files in the directory. We'll not be recursing thru the directory.
146: File[] files = file.listFiles();
147: for (int i = 0; i < files.length; i++) {
148: file = files[i];
149: if (file.isFile()) {
150: if (file.lastModified() > time) {
151: if (log.isDebugEnabled())
152: log
153: .debug(file.getAbsolutePath()
154: + " has been modified. The Cache will be flushed.");
155: m_cache.clear();
156: break;
157: }
158: }
159: }
160: }
161: }
162: }
163:
164: /** This thread class will monitor the files for any changes. It will flush the associated cache, in case any changes are detected in the files.
165: */
166: public class CacheSourceMonitorThread extends Thread {
167: /** This method will be invoked by the JVM. It monitors the files for changes at the specified frequency, until the thread is stopped.
168: */
169: public void run() {
170: while (m_executeThread) {
171: monitor();
172: try {
173: sleep(m_millis);
174: } catch (InterruptedException e) {
175: // do nothing
176: }
177: }
178: }
179: }
180:
181: }
|