merging the Mainsoft branch to the trunk
[mono.git] / mcs / class / System.Web / System.Web.Caching / CacheDependency.cs
1 // 
2 // System.Web.Caching.CacheDependency
3 //
4 // Authors:
5 //      Patrik Torstensson
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 using System;
32 using System.IO;
33 using System.Web;
34
35 namespace System.Web.Caching
36 {
37         internal class CacheDependencyChangedArgs : EventArgs
38         {
39                 string key;
40
41                 public CacheDependencyChangedArgs (string key)
42                 {
43                         this.key = key;
44                 }
45
46                 public string Key {
47                         get { return key; }
48                 }
49         }
50
51         internal delegate void CacheDependencyChangedHandler (object sender, CacheDependencyChangedArgs args);
52
53         public sealed class CacheDependency : IDisposable
54         {
55                 static string [] noStrings = new string [0];
56                 static CacheDependency noDependency = new CacheDependency ();
57                 bool changed;
58                 bool disposed;
59                 CacheEntry [] entries;
60                 CacheItemRemovedCallback removedDelegate;
61                 FileSystemWatcher [] watchers;
62
63                 private CacheDependency ()
64                 {
65                 }
66
67                 public CacheDependency (string filename)
68                         : this (filename, DateTime.MaxValue)
69                 {
70                 }
71
72                 public CacheDependency (string filename, DateTime start)
73                         : this (new string [] {filename}, null, null, start)
74                 {
75                 }
76
77                 public CacheDependency (string [] filenames)
78                         : this (filenames, null, null, DateTime.MaxValue)
79                 {
80                 }
81
82                 public CacheDependency (string [] filenames, DateTime start)
83                         : this (filenames, null, null, start)
84                 {
85                 }
86
87                 public CacheDependency (string [] filenames, string [] cachekeys)
88                         : this (filenames, cachekeys, null, DateTime.MaxValue)
89                 {
90                 }
91
92                 public CacheDependency (string [] filenames, string [] cachekeys, DateTime start)
93                         : this (filenames, cachekeys, null, start)
94                 {
95                 }
96
97                 public CacheDependency (string [] filenames, string [] cachekeys, CacheDependency dependency)
98                         : this (filenames, cachekeys, dependency, DateTime.MaxValue)
99                 {
100                 }
101
102                 public CacheDependency (string [] filenames,
103                                         string [] cachekeys,
104                                         CacheDependency dependency,
105                                         DateTime start)
106                 {
107                         Cache cache = HttpRuntime.Cache;
108
109                         if (filenames == null)
110                                 filenames = noStrings;
111
112                         foreach (string file in filenames) {
113                                 if (file == null)
114                                         throw new ArgumentNullException ("filenames");
115                         }
116
117                         if (cachekeys == null)
118                                 cachekeys = noStrings;
119
120                         int missing_keys = 0;
121                         foreach (string ck in cachekeys) {
122                                 if (ck == null)
123                                         throw new ArgumentNullException ("cachekeys");
124                                 if (cache.GetEntry (ck) == null)
125                                         missing_keys++;
126                         }
127
128                         if (dependency == null)
129                                 dependency = noDependency;
130
131
132                         this.changed = dependency.changed;
133                         if (changed == true)
134                                 return;
135
136                         int nentries = cachekeys.Length + ((dependency.entries == null) ? 0 :
137                                                                   dependency.entries.Length) - missing_keys;
138
139                         if (nentries != 0) {
140                                 this.removedDelegate = new CacheItemRemovedCallback (CacheItemRemoved);
141                                 this.entries = new CacheEntry [nentries];
142                                 
143                                 int i = 0;
144                                 if (dependency.entries != null) {
145                                         foreach (CacheEntry entry in dependency.entries) {
146                                                 entry._onRemoved += removedDelegate;
147                                                 entries [i++] = entry;
148                                         }
149                                 }
150
151                                 for (int c=0; c<cachekeys.Length; c++) {
152                                         CacheEntry entry = cache.GetEntry (cachekeys [c]);
153                                         if (entry == null)
154                                                 continue;
155                                         entry._onRemoved += removedDelegate;
156                                         entries [i++] = entry;
157                                 }
158                         }
159
160                         if (filenames.Length > 0) {
161                                 watchers = new FileSystemWatcher [filenames.Length];
162                                 for (int i=0; i<filenames.Length; i++)
163                                         watchers [i] = CreateWatcher (filenames [i]);
164                         }
165                 }
166
167                 private FileSystemWatcher CreateWatcher (string file)
168                 {
169                         FileSystemWatcher watcher = new FileSystemWatcher ();
170
171                         watcher.Path = Path.GetFullPath (Path.GetDirectoryName (file));
172                         watcher.Filter = Path.GetFileName (file);
173
174                         watcher.Changed += new FileSystemEventHandler (OnFileChanged);
175                         watcher.Created += new FileSystemEventHandler (OnFileChanged);
176                         watcher.Deleted += new FileSystemEventHandler (OnFileChanged);
177
178                         watcher.EnableRaisingEvents = true;
179
180                         return watcher;
181                 }
182
183                 private void OnFileChanged (object sender, FileSystemEventArgs e)
184                 {
185                         OnChanged (sender, e);
186                 }
187
188                 void CacheItemRemoved (string key, object value, CacheItemRemovedReason reason)
189                 {
190                         OnChanged (this, EventArgs.Empty);
191                 }
192
193                 void OnChanged (object sender, EventArgs args)
194                 {
195                         if (changed || disposed)
196                                 return;
197
198                         changed = true;
199                         if (Changed != null)
200                                 Changed (this, new CacheDependencyChangedArgs (null));
201                 }
202
203                 public void Dispose ()
204                 {
205                         for (int i=0; i<watchers.Length; i++)
206                                 watchers [i].Dispose ();
207                 }
208
209                 public bool HasChanged
210                 {
211                         get { return changed; }
212                 }
213
214                 internal CacheEntry [] GetCacheEntries ()
215                 {
216                         return entries;
217                 }
218
219                 internal event CacheDependencyChangedHandler Changed;
220         }
221 }
222