    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    }