2008-09-26 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Caching / CacheDependency.cs
1 //
2 // System.Web.Caching.CachedDependency
3 //
4 // Author(s):
5 //  Lluis Sanchez (lluis@ximian.com)
6 //
7 // (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System.Collections;
30 using System.ComponentModel;
31 using System.IO;
32 using System.Security.Permissions;
33 #if NET_2_0
34 using System.Text;
35 #endif
36
37 namespace System.Web.Caching
38 {
39 #if NET_2_0
40         // CAS
41         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
42         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
43         public class CacheDependency: IDisposable {
44 #else
45         // CAS - no InheritanceDemand here as the class is sealed
46         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47         public sealed class CacheDependency: IDisposable {
48 #endif
49                 static readonly object dependencyChangedEvent = new object ();
50                 string[] cachekeys;
51                 CacheDependency dependency;
52                 DateTime start;
53                 Cache cache;
54                 FileSystemWatcher[] watchers;
55                 bool hasChanged;
56 #if NET_2_0
57                 bool used;
58                 DateTime utcLastModified;
59 #endif
60                 object locker = new object ();
61                 EventHandlerList events = new EventHandlerList ();
62                 
63                 internal event EventHandler DependencyChanged {
64                         add { events.AddHandler (dependencyChangedEvent, value); }
65                         remove { events.RemoveHandler (dependencyChangedEvent, value); }
66                 }
67                 
68 #if NET_2_0
69                 public CacheDependency (): this (null, null, null, DateTime.Now)
70                 {
71                 }
72 #endif
73                 
74                 public CacheDependency (string filename): this (new string[] { filename }, null, null, DateTime.Now)
75                 {
76                 }
77                 
78                 public CacheDependency (string[] filenames): this (filenames, null, null, DateTime.Now)
79                 {
80                 }
81                 
82                 public CacheDependency (string filename, DateTime start): this (new string[] { filename }, null, null, start)
83                 {
84                 }
85
86                 public CacheDependency (string [] filenames, DateTime start)
87                         : this (filenames, null, null, start)
88                 {
89                 }
90
91                 public CacheDependency (string[] filenames, string[] cachekeys): this (filenames, cachekeys, null, DateTime.Now)
92                 {
93                 }
94                 
95                 public CacheDependency (string[] filenames, string[] cachekeys, CacheDependency dependency): this (filenames, cachekeys, dependency, DateTime.Now)
96                 {
97                 }
98                 
99                 public CacheDependency (string[] filenames, string[] cachekeys, DateTime start): this (filenames, cachekeys, null, start)
100                 {
101                 }
102                 
103                 public CacheDependency (string[] filenames, string[] cachekeys, CacheDependency dependency, DateTime start)
104                 {
105                         if (filenames != null) {
106                                 watchers = new FileSystemWatcher [filenames.Length];
107                                 for (int n=0; n<filenames.Length; n++) {
108                                         FileSystemWatcher watcher = new FileSystemWatcher ();
109                                         if (Directory.Exists (filenames [n])) {
110                                                 watcher.Path = filenames [n];
111                                         } else {
112                                                 string parentPath = Path.GetDirectoryName (filenames [n]);
113                                                 if (parentPath != null && Directory.Exists (parentPath)) {
114                                                         watcher.Path = parentPath;
115                                                         watcher.Filter = Path.GetFileName (filenames [n]);
116                                                 } else
117                                                         continue;
118                                         }
119                                         watcher.NotifyFilter |= NotifyFilters.Size;
120                                         watcher.Created += new FileSystemEventHandler (OnChanged);
121                                         watcher.Changed += new FileSystemEventHandler (OnChanged);
122                                         watcher.Deleted += new FileSystemEventHandler (OnChanged);
123                                         watcher.Renamed += new RenamedEventHandler (OnChanged);
124                                         watcher.EnableRaisingEvents = true;
125                                         watchers [n] = watcher;
126                                 }
127                         }
128                         this.cachekeys = cachekeys;
129                         this.dependency = dependency;
130                         if (dependency != null)
131                                 dependency.DependencyChanged += new EventHandler (OnChildDependencyChanged);
132                         this.start = start;
133
134 #if NET_2_0
135                         FinishInit ();
136 #endif
137                 }
138
139 #if NET_2_0
140                 public virtual string GetUniqueID ()
141                 {
142                         StringBuilder sb = new StringBuilder ();
143                         lock (locker) {
144                                 if (watchers != null)
145                                         foreach (FileSystemWatcher fsw in watchers)
146                                                 if (fsw != null && fsw.Path != null && fsw.Path.Length != 0)
147                                                         sb.AppendFormat ("_{0}", fsw.Path);
148                         }
149
150                         if (cachekeys != null)
151                                 foreach (string key in cachekeys)
152                                         sb.AppendFormat ("_{0}", key);
153                         return sb.ToString ();
154                 }
155 #endif
156                 
157                 void OnChanged (object sender, FileSystemEventArgs args)
158                 {
159                         OnDependencyChanged (sender, args);
160                 }
161
162                 bool DoOnChanged ()
163                 {
164                         if (DateTime.Now < start)
165                                 return false;
166                         hasChanged = true;
167 #if NET_2_0
168                         utcLastModified = DateTime.UtcNow;
169 #endif
170                         DisposeWatchers ();
171                         
172                         if (cache != null)
173                                 cache.CheckDependencies ();
174
175                         return true;
176                 }
177                 
178                 void DisposeWatchers ()
179                 {
180                         lock (locker) {
181                                 if (watchers != null) {
182                                         foreach (FileSystemWatcher w in watchers)
183                                                 if (w != null)
184                                                         w.Dispose ();
185                                 }
186                                 watchers = null;
187                         }
188                 }
189
190                 public void Dispose ()
191                 {
192                         DependencyDispose ();
193                 }
194
195 #if NET_2_0
196                 internal virtual void DependencyDisposeInternal ()
197                 {
198                 }
199 #endif
200                 
201 #if NET_2_0
202                 protected virtual
203 #endif
204                 void DependencyDispose () 
205                 {
206 #if NET_2_0
207                         DependencyDisposeInternal ();
208 #endif
209                         DisposeWatchers ();
210                         if (dependency != null)
211                                 dependency.DependencyChanged -= new EventHandler (OnChildDependencyChanged);
212                         cache = null;
213                 }
214                 
215                 internal void SetCache (Cache c)
216                 {
217                         cache = c;
218 #if NET_2_0
219                         used = c != null;
220 #endif
221                 }
222                 
223 #if NET_2_0
224                 protected internal void FinishInit () 
225                 {
226                         utcLastModified = DateTime.UtcNow;
227                 }
228
229                 internal bool IsUsed {
230                         get { return used; }
231                 }
232
233                 internal DateTime Start {
234                         get { return start; }
235                         set { start = value; }
236                 }
237
238                 public DateTime UtcLastModified {
239                         get {
240                                 return utcLastModified;
241                         }
242                 }
243
244                 protected void SetUtcLastModified (DateTime utcLastModified) 
245                 {
246                         this.utcLastModified = utcLastModified;
247                 }
248 #endif
249                 
250                 public bool HasChanged {
251                         get {
252                                 if (hasChanged)
253                                         return true;
254
255                                 if (DateTime.Now < start)
256                                         return false;
257
258                                 if (cache != null && cachekeys != null) {
259                                         foreach (string key in cachekeys) {
260                                                 if (cache.GetKeyLastChange (key) > start) {
261                                                         hasChanged = true;
262                                                         break;
263                                                 }
264                                         }
265                                 }
266                                 if (hasChanged)
267                                         DisposeWatchers ();
268
269                                 return hasChanged;
270                         }
271                 }
272                 
273                 void OnChildDependencyChanged (object o, EventArgs e)
274                 {
275                         hasChanged = true;
276                         OnDependencyChanged (o, e);
277                 }
278                 
279                 void OnDependencyChanged (object sender, EventArgs e)
280                 {
281                         if (!DoOnChanged ())
282                                 return;
283
284                         EventHandler eh = events [dependencyChangedEvent] as EventHandler;
285                         if (eh != null)
286                                 eh (sender, e);
287                 }
288                 
289 #if NET_2_0
290                 protected
291 #else
292                 internal
293 #endif
294                 void NotifyDependencyChanged (object sender, EventArgs e) 
295                 {
296                         OnDependencyChanged (sender, e);
297                 }
298
299
300         }
301 }