Author: rgrabowski
Date: Sun Aug 24 10:00:02 2008
New Revision: 688527

URL: http://svn.apache.org/viewvc?rev=688527&view=rev
Log:
Fix for LOG4NET-158. XMLConfigurator.ConfigureAndWatch() won't leak resources 
when called multiple times. Internal FileWatcher is properly disposed when a 
change is detected.

Modified:
    logging/log4net/trunk/src/Config/XmlConfigurator.cs

Modified: logging/log4net/trunk/src/Config/XmlConfigurator.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Config/XmlConfigurator.cs?rev=688527&r1=688526&r2=688527&view=diff
==============================================================================
--- logging/log4net/trunk/src/Config/XmlConfigurator.cs (original)
+++ logging/log4net/trunk/src/Config/XmlConfigurator.cs Sun Aug 24 10:00:02 2008
@@ -870,9 +870,23 @@
 
                                try
                                {
-                                       // Create a watch handler that will 
reload the
-                                       // configuration whenever the config 
file is modified.
-                                       
ConfigureAndWatchHandler.StartWatching(repository, configFile);
+                    lock (m_repositoryName2ConfigAndWatchHandler)
+                    {
+                        // support multiple repositories each having their own 
watcher
+                        ConfigureAndWatchHandler handler =
+                            
(ConfigureAndWatchHandler)m_repositoryName2ConfigAndWatchHandler[repository.Name];
+
+                        if (handler != null)
+                        {
+                            
m_repositoryName2ConfigAndWatchHandler.Remove(repository.Name);
+                            handler.Dispose();
+                        }
+
+                        // Create and start a watch handler that will reload 
the
+                        // configuration whenever the config file is modified.
+                        handler = new ConfigureAndWatchHandler(repository, 
configFile);
+                        
m_repositoryName2ConfigAndWatchHandler[repository.Name] = handler;
+                    }
                                }
                                catch(Exception ex)
                                {
@@ -903,24 +917,9 @@
                /// elapse.
                /// </para>
                /// </remarks>
-               private sealed class ConfigureAndWatchHandler
+               private sealed class ConfigureAndWatchHandler : IDisposable
                {
                        /// <summary>
-                       /// Watch a specified config file used to configure a 
repository
-                       /// </summary>
-                       /// <param name="repository">The repository to 
configure.</param>
-                       /// <param name="configFile">The configuration file to 
watch.</param>
-                       /// <remarks>
-                       /// <para>
-                       /// Watch a specified config file used to configure a 
repository
-                       /// </para>
-                       /// </remarks>
-                       internal static void StartWatching(ILoggerRepository 
repository, FileInfo configFile)
-                       {
-                               new ConfigureAndWatchHandler(repository, 
configFile);
-                       }
-
-                       /// <summary>
                        /// Holds the FileInfo used to configure the 
XmlConfigurator
                        /// </summary>
                        private FileInfo m_configFile;
@@ -941,8 +940,15 @@
                        /// </summary>
                        private const int TimeoutMillis = 500;
 
+            /// <summary>
+            /// Watches file for changes. This object should be disposed when 
no longer
+            /// needed to free system handles on the watched resources.
+            /// </summary>
+            private FileSystemWatcher m_watcher;
+
                        /// <summary>
-                       /// Initializes a new instance of the <see 
cref="ConfigureAndWatchHandler" /> class.
+                       /// Initializes a new instance of the <see 
cref="ConfigureAndWatchHandler" /> class to
+            /// watch a specified config file used to configure a repository.
                        /// </summary>
                        /// <param name="repository">The repository to 
configure.</param>
                        /// <param name="configFile">The configuration file to 
watch.</param>
@@ -951,31 +957,31 @@
                        /// Initializes a new instance of the <see 
cref="ConfigureAndWatchHandler" /> class.
                        /// </para>
                        /// </remarks>
-                       private ConfigureAndWatchHandler(ILoggerRepository 
repository, FileInfo configFile)
+                       public ConfigureAndWatchHandler(ILoggerRepository 
repository, FileInfo configFile)
                        {
                                m_repository = repository;
                                m_configFile = configFile;
 
                                // Create a new FileSystemWatcher and set its 
properties.
-                               FileSystemWatcher watcher = new 
FileSystemWatcher();
+                               m_watcher = new FileSystemWatcher();
 
-                               watcher.Path = m_configFile.DirectoryName;
-                               watcher.Filter = m_configFile.Name;
+                               m_watcher.Path = m_configFile.DirectoryName;
+                               m_watcher.Filter = m_configFile.Name;
 
                                // Set the notification filters
-                               watcher.NotifyFilter = 
NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.FileName;
+                               m_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(ConfigureAndWatchHandler_OnChanged);
-                               watcher.Created += new 
FileSystemEventHandler(ConfigureAndWatchHandler_OnChanged);
-                               watcher.Deleted += new 
FileSystemEventHandler(ConfigureAndWatchHandler_OnChanged);
-                               watcher.Renamed += new 
RenamedEventHandler(ConfigureAndWatchHandler_OnRenamed);
+                               m_watcher.Changed += new 
FileSystemEventHandler(ConfigureAndWatchHandler_OnChanged);
+                               m_watcher.Created += new 
FileSystemEventHandler(ConfigureAndWatchHandler_OnChanged);
+                               m_watcher.Deleted += new 
FileSystemEventHandler(ConfigureAndWatchHandler_OnChanged);
+                               m_watcher.Renamed += new 
RenamedEventHandler(ConfigureAndWatchHandler_OnRenamed);
 
                                // Begin watching.
-                               watcher.EnableRaisingEvents = true;
+                               m_watcher.EnableRaisingEvents = true;
 
                                // Create the timer that will be used to 
deliver events. Set as disabled
-                               m_timer = new Timer(new 
TimerCallback(OnWatchedFileChange), null, Timeout.Infinite, Timeout.Infinite);
+                m_timer = new Timer(new TimerCallback(OnWatchedFileChange), 
null, Timeout.Infinite, Timeout.Infinite);
                        }
 
                        /// <summary>
@@ -1024,6 +1030,16 @@
                        {
                                XmlConfigurator.InternalConfigure(m_repository, 
m_configFile);
                        }
+
+            /// <summary>
+            /// Release the handles held by the watcher and timer.
+            /// </summary>
+            public void Dispose()
+            {
+                m_watcher.EnableRaisingEvents = false;
+                m_watcher.Dispose();
+                m_timer.Dispose();
+            }
                }
 #endif
 
@@ -1083,6 +1099,13 @@
 
            #region Private Static Fields
 
+        /// <summary>
+        /// Maps repository names to ConfigAndWatchHandler instances to allow 
a particular
+        /// ConfigAndWatchHandler to dispose of its FileSystemWatcher when a 
repository is 
+        /// reconfigured.
+        /// </summary>
+        private readonly static Hashtable 
m_repositoryName2ConfigAndWatchHandler = new Hashtable();
+
            /// <summary>
            /// The fully qualified type of the XmlConfigurator class.
            /// </summary>


Reply via email to