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
018 package org.apache.commons.jci.monitor;
019
020 import java.io.File;
021 import java.util.Collections;
022 import java.util.HashMap;
023 import java.util.Map;
024
025 import org.apache.commons.logging.Log;
026 import org.apache.commons.logging.LogFactory;
027
028 /**
029 * It's a runnable that spawns of a monitoring thread triggering the
030 * the observers and managing the their listeners.
031 *
032 * @author tcurdt
033 */
034 public final class FilesystemAlterationMonitor implements Runnable {
035
036 private final Log log = LogFactory.getLog(FilesystemAlterationMonitor.class);
037
038 private final Object observersLock = new Object();
039 private Map<File, FilesystemAlterationObserver> observers = Collections.unmodifiableMap(new HashMap<File, FilesystemAlterationObserver>());
040
041 /** delay between calls to {@link FilesystemAlterationObserver#checkAndNotify()}, default 3000 ms */
042 private volatile long delay = 3000; // volatile because shared with daemon thread
043 private Thread thread = null;
044
045 private volatile boolean running = true;
046
047 public FilesystemAlterationMonitor() {
048 }
049
050
051 public void start() {
052 thread = new Thread(this);
053 thread.setName("Filesystem Alteration Monitor");
054 thread.setDaemon(true);
055 thread.start();
056 }
057
058
059 public void stop() {
060 running = false;
061
062 if (thread != null) {
063 try {
064 thread.join(delay);
065 } catch (InterruptedException e) {
066 }
067 }
068 }
069
070
071 /**
072 * Set the delay between calls to the observers.
073 *
074 * @param pDelay the delay in milliseconds (default if not set 3000 ms)
075 */
076 public void setInterval( final long pDelay ) {
077 delay = pDelay;
078 }
079
080
081 public void addListener( final File pRoot, final FilesystemAlterationListener pListener ) {
082
083 FilesystemAlterationObserver observer;
084
085 synchronized (observersLock) {
086 observer = observers.get(pRoot);
087
088 if (observer == null) {
089 final Map<File, FilesystemAlterationObserver> newObservers = new HashMap<File, FilesystemAlterationObserver>(observers);
090 observer = new FilesystemAlterationObserverImpl(pRoot);
091 newObservers.put(pRoot, observer);
092 observers = Collections.unmodifiableMap(newObservers);
093 }
094 }
095
096 observer.addListener(pListener);
097 }
098
099 public void removeListener( final FilesystemAlterationListener pListener ) {
100 synchronized (observersLock) {
101 for (FilesystemAlterationObserver observer : observers.values()) {
102 observer.removeListener(pListener);
103 // FIXME: remove observer if there are no listeners?
104 }
105 }
106 }
107
108 public FilesystemAlterationListener[] getListenersFor( final File pRoot ) {
109 final FilesystemAlterationObserver observer = observers.get(pRoot);
110
111 if (observer == null) {
112 return new FilesystemAlterationListener[0];
113 }
114
115 return observer.getListeners();
116 }
117
118
119 public void run() {
120 log.debug("fam running");
121
122 while (running) {
123
124 for (FilesystemAlterationObserver observer : observers.values()) {
125 observer.checkAndNotify();
126 }
127
128 try {
129 Thread.sleep(delay);
130 } catch (final InterruptedException e) {
131 }
132 }
133
134 log.debug("fam exiting");
135 }
136
137 }