2 // HostFileChangeMonitor.cs
5 // Marek Habersack <mhabersack@novell.com>
7 // Copyright (C) 2010 Novell, Inc. (http://novell.com/)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Collections.Generic;
30 using System.Collections.ObjectModel;
32 using System.Runtime.Caching.Hosting;
35 namespace System.Runtime.Caching
37 public sealed class HostFileChangeMonitor : FileChangeMonitor
39 const long INVALID_FILE_SIZE = -1L;
40 static readonly object notificationSystemLock = new object ();
41 static readonly DateTime missingFileTimeStamp = new DateTime (0x701CE1722770000);
42 static IFileChangeNotificationSystem notificationSystem;
43 static bool notificationSystemSetFromHost;
45 ReadOnlyCollection <string> filePaths;
46 DateTime lastModified;
48 bool disposeNotificationSystem;
50 Dictionary <string, object> notificationStates;
52 public override ReadOnlyCollection<string> FilePaths {
53 get { return filePaths;}
56 public override DateTimeOffset LastModified {
57 get { return lastModified; }
60 public override string UniqueId {
61 get { return uniqueId; }
64 public HostFileChangeMonitor (IList<string> filePaths)
66 if (filePaths == null)
67 throw new ArgumentNullException ("filePaths");
69 if (filePaths.Count == 0)
70 throw new ArgumentException ("filePaths contains zero items.");
72 var list = new List <string> (filePaths.Count);
73 var sb = new StringBuilder ();
74 lastModified = DateTime.MinValue;
77 bool ignoreForUniqueId;
79 foreach (string p in filePaths) {
80 if (String.IsNullOrEmpty (p))
81 throw new ArgumentException ("A path in the filePaths list is null or an empty string.");
83 if (!Path.IsPathRooted (p))
84 throw new ArgumentException ("Absolute path information is required.");
86 if (list.Contains (p))
87 ignoreForUniqueId = true;
89 ignoreForUniqueId = false;
93 if (ignoreForUniqueId)
96 if (Directory.Exists (p)) {
97 var di = new DirectoryInfo (p);
98 lastWrite = di.LastWriteTimeUtc;
99 size = INVALID_FILE_SIZE;
100 } else if (File.Exists (p)) {
101 var fi = new FileInfo (p);
102 lastWrite = fi.LastWriteTimeUtc;
105 lastWrite = missingFileTimeStamp;
106 size = INVALID_FILE_SIZE;
109 if (lastWrite > lastModified)
110 lastModified = lastWrite;
112 sb.AppendFormat ("{0}{1:X}{2:X}", p, lastWrite.Ticks, (ulong)size);
115 this.filePaths = new ReadOnlyCollection <string> (list);
116 this.uniqueId = sb.ToString ();
118 bool initComplete = false;
123 InitializationComplete ();
129 void InitMonitoring ()
131 IServiceProvider host;
132 if (!notificationSystemSetFromHost && (host = ObjectCache.Host) != null) {
133 lock (notificationSystemLock) {
134 if (!notificationSystemSetFromHost) {
136 notificationSystem = host.GetService (typeof (IFileChangeNotificationSystem)) as IFileChangeNotificationSystem;
138 if (notificationSystem != null)
139 notificationSystemSetFromHost = true;
144 if (!notificationSystemSetFromHost) {
145 notificationSystem = new FileChangeNotificationSystem ();
146 disposeNotificationSystem = true;
151 // TODO: what are these two used for?
152 DateTimeOffset lastWriteTime;
155 notificationStates = new Dictionary <string, object> (filePaths.Count, Helpers.StringEqualityComparer);
156 foreach (string path in filePaths) {
157 if (notificationStates.ContainsKey (path))
158 continue; // silently ignore dupes
160 notificationSystem.StartMonitoring (path, OnChanged, out state, out lastWriteTime, out fileSize);
161 notificationStates.Add (path, state);
165 protected override void Dispose (bool disposing)
167 if (disposing && notificationSystem != null) {
170 foreach (var de in notificationStates) {
176 notificationSystem.StopMonitoring (de.Key, state);
182 if (disposeNotificationSystem) {
183 var fcns = notificationSystem as FileChangeNotificationSystem;
188 notificationSystem = null;