    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    }