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.util.List;
020 import java.util.concurrent.CopyOnWriteArrayList;
021
022 /**
023 * A runnable that spawns a monitoring thread triggering any
024 * registered {@link FileAlterationObserver} at a specified interval.
025 *
026 * @see FileAlterationObserver
027 * @version $Id: FileAlterationMonitor.java 1022799 2010-10-15 00:56:13Z niallp $
028 * @since Commons IO 2.0
029 */
030 public final class FileAlterationMonitor implements Runnable {
031
032 private final long interval;
033 private final List<FileAlterationObserver> observers = new CopyOnWriteArrayList<FileAlterationObserver>();
034 private Thread thread = null;
035 private volatile boolean running = false;
036
037 /**
038 * Construct a monitor with a default interval of 10 seconds.
039 */
040 public FileAlterationMonitor() {
041 this(10000);
042 }
043
044 /**
045 * Construct a monitor with the specified interval.
046 *
047 * @param interval The amount of time in miliseconds to wait between
048 * checks of the file system
049 */
050 public FileAlterationMonitor(long interval) {
051 this.interval = interval;
052 }
053
054 /**
055 * Return the interval.
056 *
057 * @return the interval
058 */
059 public long getInterval() {
060 return interval;
061 }
062
063 /**
064 * Construct a monitor with the specified interval and set of observers.
065 *
066 * @param interval The amount of time in miliseconds to wait between
067 * checks of the file system
068 * @param observers The set of observers to add to the monitor.
069 */
070 public FileAlterationMonitor(long interval, FileAlterationObserver... observers) {
071 this(interval);
072 if (observers != null) {
073 for (FileAlterationObserver observer : observers) {
074 addObserver(observer);
075 }
076 }
077 }
078
079 /**
080 * Add a file system observer to this monitor.
081 *
082 * @param observer The file system observer to add
083 */
084 public void addObserver(final FileAlterationObserver observer) {
085 if (observer != null) {
086 observers.add(observer);
087 }
088 }
089
090 /**
091 * Remove a file system observer from this monitor.
092 *
093 * @param observer The file system observer to remove
094 */
095 public void removeObserver(final FileAlterationObserver observer) {
096 if (observer != null) {
097 while (observers.remove(observer)) {
098 }
099 }
100 }
101
102 /**
103 * Returns the set of {@link FileAlterationObserver} registered with
104 * this monitor.
105 *
106 * @return The set of {@link FileAlterationObserver}
107 */
108 public Iterable<FileAlterationObserver> getObservers() {
109 return observers;
110 }
111
112 /**
113 * Start monitoring.
114 *
115 * @throws Exception if an error occurs initializing the observer
116 */
117 public synchronized void start() throws Exception {
118 if (running) {
119 throw new IllegalStateException("Monitor is already running");
120 }
121 for (FileAlterationObserver observer : observers) {
122 observer.initialize();
123 }
124 running = true;
125 thread = new Thread(this);
126 thread.start();
127 }
128
129 /**
130 * Stop monitoring.
131 *
132 * @throws Exception if an error occurs initializing the observer
133 */
134 public synchronized void stop() throws Exception {
135 if (running == false) {
136 throw new IllegalStateException("Monitor is not running");
137 }
138 running = false;
139 try {
140 thread.join(interval);
141 } catch (InterruptedException e) {
142 Thread.currentThread().interrupt();
143 }
144 for (FileAlterationObserver observer : observers) {
145 observer.destroy();
146 }
147 }
148
149 /**
150 * Run.
151 */
152 public void run() {
153 while (running) {
154 for (FileAlterationObserver observer : observers) {
155 observer.checkAndNotify();
156 }
157 if (!running) {
158 break;
159 }
160 try {
161 Thread.sleep(interval);
162 } catch (final InterruptedException ignored) {
163 }
164 }
165 }
166 }