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