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 }