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 }