#region Apache Notice /***************************************************************************** * $Header: $ * $Revision: $ * $Date: $ * * iBATIS.NET Data Mapper * Copyright (C) 2004 - Gilles Bayon * * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ********************************************************************************/ #endregion using System; using System.Collections; using System.IO; using System.Threading; using IBatisNet.Common.Logging; namespace IBatisNet.Common.Utilities { /// /// Represents the method that handles calls from Configure. /// /// /// obj is a null object in a DaoManager context. /// obj is the reconfigured sqlMap in a SqlMap context. /// public delegate void ConfigureHandler(object obj); /// /// /// public struct StateConfig { /// /// Master Config File name. /// public string FileName; /// /// Delegate called when a file is changed, use it to rebuild. /// public ConfigureHandler ConfigureHandler; } /// /// Class used to watch config files. /// /// /// Uses the to monitor /// changes to a specified file. Because multiple change notifications /// may be raised when the file is modified, a timer is used to /// compress the notifications into a single event. The timer /// waits for time before delivering /// the event notification. If any further /// change notifications arrive while the timer is waiting it /// is reset and waits again for to /// elaps. /// public sealed class ConfigWatcherHandler { #region Fields private static readonly ILog _logger = LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType ); /// /// The timer used to compress the notification events. /// private Timer _timer = null; /// /// A list of configuration files to watch. /// private static ArrayList _filesToWatch = new ArrayList(); /// /// The list of FileSystemWatcher. /// private static ArrayList _filesWatcher = new ArrayList(); /// /// The default amount of time to wait after receiving notification /// before reloading the config file. /// private const int TimoutMillis = 500; #endregion #region Constructor (s) / Destructor /// ///- /// /// /// Represent the call context of the SqlMap or DaoManager ConfigureAndWatch method call. /// /// public ConfigWatcherHandler(TimerCallback onWhatchedFileChange, StateConfig state) { for(int index = 0; index < _filesToWatch.Count; index++) { FileInfo configFile = (FileInfo)_filesToWatch[index]; // Create a new FileSystemWatcher and set its properties. FileSystemWatcher watcher = new FileSystemWatcher(); watcher.Path = configFile.DirectoryName; watcher.Filter = configFile.Name; // Set the notification filters watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.FileName; // Add event handlers. OnChanged will do for all event handlers that fire a FileSystemEventArgs watcher.Changed += new FileSystemEventHandler(ConfigWatcherHandler_OnChanged); watcher.Created += new FileSystemEventHandler(ConfigWatcherHandler_OnChanged); watcher.Deleted += new FileSystemEventHandler(ConfigWatcherHandler_OnChanged); watcher.Renamed += new RenamedEventHandler(ConfigWatcherHandler_OnRenamed); // Begin watching. watcher.EnableRaisingEvents = true; _filesWatcher.Add( watcher ); // Create the timer that will be used to deliver events. Set as disabled _timer = new Timer(onWhatchedFileChange, state, Timeout.Infinite, Timeout.Infinite); } } #endregion #region Methods /// /// Add a file to be monitored. /// /// public static void AddFileToWatch(FileInfo configFile) { _filesToWatch.Add( configFile ); } /// /// Reset the list of files being monitored. /// public static void ClearFilesMonitored() { _filesToWatch.Clear(); // Kill all FileSystemWatcher for(int index = 0; index < _filesWatcher.Count; index++) { FileSystemWatcher fileWatcher = (FileSystemWatcher)_filesWatcher[index]; fileWatcher.EnableRaisingEvents = false; fileWatcher.Dispose(); } } /// /// Event handler used by . /// /// The firing the event. /// The argument indicates the file that caused the event to be fired. /// /// This handler reloads the configuration from the file when the event is fired. /// private void ConfigWatcherHandler_OnChanged(object source, FileSystemEventArgs e) { if (_logger.IsDebugEnabled) { _logger.Debug("ConfigWatcherHandler : "+e.ChangeType+" [" + e.Name + "]"); } // Deliver the event in TimoutMillis time // timer will fire only once _timer.Change(TimoutMillis, Timeout.Infinite); } /// /// Event handler used by . /// /// The firing the event. /// The argument indicates the file that caused the event to be fired. /// /// This handler reloads the configuration from the file when the event is fired. /// private void ConfigWatcherHandler_OnRenamed(object source, RenamedEventArgs e) { if (_logger.IsDebugEnabled) { _logger.Debug("ConfigWatcherHandler : " + e.ChangeType + " [" + e.OldName + "/" +e.Name +"]"); } // Deliver the event in TimoutMillis time // timer will fire only once _timer.Change(TimoutMillis, Timeout.Infinite); } #endregion } }