2010-01-20 Zoltan Varga <vargaz@gmail.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 using System.Text;
34
35 namespace System.Web.Caching
36 {
37         // CAS
38         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
39         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
40         public class CacheDependency: IDisposable
41         {
42                 static readonly object dependencyChangedEvent = new object ();
43                 string[] cachekeys;
44                 CacheDependency dependency;
45                 DateTime start;
46                 Cache cache;
47                 FileSystemWatcher[] watchers;
48                 bool hasChanged;
49                 bool used;
50                 DateTime utcLastModified;
51                 object locker = new object ();
52                 EventHandlerList events = new EventHandlerList ();
53                 
54                 internal event EventHandler DependencyChanged {
55                         add { events.AddHandler (dependencyChangedEvent, value); }
56                         remove { events.RemoveHandler (dependencyChangedEvent, value); }
57                 }
58                 
59                 public CacheDependency (): this (null, null, null, DateTime.Now)
60                 {
61                 }
62                 
63                 public CacheDependency (string filename): this (new string[] { filename }, null, null, DateTime.Now)
64                 {
65                 }
66                 
67                 public CacheDependency (string[] filenames): this (filenames, null, null, DateTime.Now)
68                 {
69                 }
70                 
71                 public CacheDependency (string filename, DateTime start): this (new string[] { filename }, null, null, start)
72                 {
73                 }
74
75                 public CacheDependency (string [] filenames, DateTime start)
76                         : this (filenames, null, null, start)
77                 {
78                 }
79
80                 public CacheDependency (string[] filenames, string[] cachekeys): this (filenames, cachekeys, null, DateTime.Now)
81                 {
82                 }
83                 
84                 public CacheDependency (string[] filenames, string[] cachekeys, CacheDependency dependency): this (filenames, cachekeys, dependency, DateTime.Now)
85                 {
86                 }
87                 
88                 public CacheDependency (string[] filenames, string[] cachekeys, DateTime start): this (filenames, cachekeys, null, start)
89                 {
90                 }
91                 
92                 public CacheDependency (string[] filenames, string[] cachekeys, CacheDependency dependency, DateTime start)
93                 {
94                         if (filenames != null) {
95                                 watchers = new FileSystemWatcher [filenames.Length];
96                                 for (int n=0; n<filenames.Length; n++) {
97                                         FileSystemWatcher watcher = new FileSystemWatcher ();
98                                         if (Directory.Exists (filenames [n])) {
99                                                 watcher.Path = filenames [n];
100                                         } else {
101                                                 string parentPath = Path.GetDirectoryName (filenames [n]);
102                                                 if (parentPath != null && Directory.Exists (parentPath)) {
103                                                         watcher.Path = parentPath;
104                                                         watcher.Filter = Path.GetFileName (filenames [n]);
105                                                 } else
106                                                         continue;
107                                         }
108                                         watcher.NotifyFilter |= NotifyFilters.Size;
109                                         watcher.Created += new FileSystemEventHandler (OnChanged);
110                                         watcher.Changed += new FileSystemEventHandler (OnChanged);
111                                         watcher.Deleted += new FileSystemEventHandler (OnChanged);
112                                         watcher.Renamed += new RenamedEventHandler (OnChanged);
113                                         watcher.EnableRaisingEvents = true;
114                                         watchers [n] = watcher;
115                                 }
116                         }
117                         this.cachekeys = cachekeys;
118                         this.dependency = dependency;
119                         if (dependency != null)
120                                 dependency.DependencyChanged += new EventHandler (OnChildDependencyChanged);
121                         this.start = start;
122
123                         FinishInit ();
124                 }
125
126                 public virtual string GetUniqueID ()
127                 {
128                         StringBuilder sb = new StringBuilder ();
129                         lock (locker) {
130                                 if (watchers != null)
131                                         foreach (FileSystemWatcher fsw in watchers)
132                                                 if (fsw != null && fsw.Path != null && fsw.Path.Length != 0)
133                                                         sb.AppendFormat ("_{0}", fsw.Path);
134                         }
135
136                         if (cachekeys != null)
137                                 foreach (string key in cachekeys)
138                                         sb.AppendFormat ("_{0}", key);
139                         return sb.ToString ();
140                 }
141                 
142                 void OnChanged (object sender, FileSystemEventArgs args)
143                 {
144                         OnDependencyChanged (sender, args);
145                 }
146
147                 bool DoOnChanged ()
148                 {
149                         if (DateTime.Now < start)
150                                 return false;
151                         hasChanged = true;
152                         utcLastModified = DateTime.UtcNow;
153                         DisposeWatchers ();
154                         
155                         if (cache != null)
156                                 cache.CheckDependencies ();
157
158                         return true;
159                 }
160                 
161                 void DisposeWatchers ()
162                 {
163                         lock (locker) {
164                                 if (watchers != null) {
165                                         foreach (FileSystemWatcher w in watchers)
166                                                 if (w != null)
167                                                         w.Dispose ();
168                                 }
169                                 watchers = null;
170                         }
171                 }
172
173                 public void Dispose ()
174                 {
175                         DependencyDispose ();
176                 }
177
178                 internal virtual void DependencyDisposeInternal ()
179                 {
180                 }
181                 
182                 protected virtual void DependencyDispose () 
183                 {
184                         DependencyDisposeInternal ();
185                         DisposeWatchers ();
186                         if (dependency != null) {
187                                 dependency.DependencyChanged -= new EventHandler (OnChildDependencyChanged);
188                                 dependency.Dispose ();
189                         }
190                         
191                         cache = null;
192                 }
193                 
194                 internal void SetCache (Cache c)
195                 {
196                         cache = c;
197                         used = c != null;
198                 }
199                 
200                 protected internal void FinishInit () 
201                 {
202                         utcLastModified = DateTime.UtcNow;
203                 }
204
205                 internal bool IsUsed {
206                         get { return used; }
207                 }
208
209                 internal DateTime Start {
210                         get { return start; }
211                         set { start = value; }
212                 }
213
214                 public DateTime UtcLastModified {
215                         get {
216                                 return utcLastModified;
217                         }
218                 }
219
220                 protected void SetUtcLastModified (DateTime utcLastModified) 
221                 {
222                         this.utcLastModified = utcLastModified;
223                 }
224                 
225                 public bool HasChanged {
226                         get {
227                                 if (hasChanged)
228                                         return true;
229
230                                 if (DateTime.Now < start)
231                                         return false;
232
233                                 if (cache != null && cachekeys != null) {
234                                         foreach (string key in cachekeys) {
235                                                 if (cache.GetKeyLastChange (key) > start) {
236                                                         hasChanged = true;
237                                                         break;
238                                                 }
239                                         }
240                                 }
241                                 if (hasChanged)
242                                         DisposeWatchers ();
243
244                                 return hasChanged;
245                         }
246                 }
247                 
248                 void OnChildDependencyChanged (object o, EventArgs e)
249                 {
250                         hasChanged = true;
251                         OnDependencyChanged (o, e);
252                 }
253                 
254                 void OnDependencyChanged (object sender, EventArgs e)
255                 {
256                         if (!DoOnChanged ())
257                                 return;
258
259                         EventHandler eh = events [dependencyChangedEvent] as EventHandler;
260                         if (eh != null)
261                                 eh (sender, e);
262                 }               
263
264                 protected void NotifyDependencyChanged (object sender, EventArgs e) 
265                 {
266                         OnDependencyChanged (sender, e);
267                 }
268
269
270         }
271 }