-//
-// System.Web.Caching.CacheDependency
//
-// Authors:
-// Patrik Torstensson
-// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// System.Web.Caching.CachedDependency
//
-// (c) 2003 Ximian, Inc. (http://www.ximian.com)
+// Author(s):
+// Lluis Sanchez (lluis@ximian.com)
+//
+// (C) 2005 Novell, Inc (http://www.novell.com)
//
-
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
+
+using System.Collections;
using System.IO;
-using System.Web;
+using System.Security.Permissions;
+#if NET_2_0
+using System.Text;
+#endif
namespace System.Web.Caching
{
- internal class CacheDependencyChangedArgs : EventArgs
- {
- string key;
-
- public CacheDependencyChangedArgs (string key)
- {
- this.key = key;
- }
-
- public string Key {
- get { return key; }
- }
- }
-
- internal delegate void CacheDependencyChangedHandler (object sender, CacheDependencyChangedArgs args);
-
- public sealed class CacheDependency : IDisposable
- {
- static string [] noStrings = new string [0];
- static CacheDependency noDependency = new CacheDependency ();
- bool changed;
- bool disposed;
- CacheEntry [] entries;
- CacheItemRemovedCallback removedDelegate;
- FileSystemWatcher [] watchers;
-
- private CacheDependency ()
+#if NET_2_0
+ // CAS
+ [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+ [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+ public class CacheDependency: IDisposable {
+#else
+ // CAS - no InheritanceDemand here as the class is sealed
+ [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+ public sealed class CacheDependency: IDisposable {
+#endif
+ string[] cachekeys;
+ CacheDependency dependency;
+ DateTime start;
+ Cache cache;
+ FileSystemWatcher[] watchers;
+ bool hasChanged;
+#if NET_2_0
+ bool used;
+ DateTime utcLastModified;
+#endif
+ object locker = new object ();
+
+#if NET_2_0
+ public CacheDependency (): this (null, null, null, DateTime.Now)
{
}
-
- public CacheDependency (string filename)
- : this (filename, DateTime.MaxValue)
+#endif
+
+ public CacheDependency (string filename): this (new string[] { filename }, null, null, DateTime.Now)
{
}
-
- public CacheDependency (string filename, DateTime start)
- : this (new string [] {filename}, null, null, start)
+
+ public CacheDependency (string[] filenames): this (filenames, null, null, DateTime.Now)
{
}
-
- public CacheDependency (string [] filenames)
- : this (filenames, null, null, DateTime.MaxValue)
+
+ public CacheDependency (string filename, DateTime start): this (new string[] { filename }, null, null, start)
{
}
{
}
- public CacheDependency (string [] filenames, string [] cachekeys)
- : this (filenames, cachekeys, null, DateTime.MaxValue)
+ public CacheDependency (string[] filenames, string[] cachekeys): this (filenames, cachekeys, null, DateTime.Now)
{
}
-
- public CacheDependency (string [] filenames, string [] cachekeys, DateTime start)
- : this (filenames, cachekeys, null, start)
+
+ public CacheDependency (string[] filenames, string[] cachekeys, CacheDependency dependency): this (filenames, cachekeys, dependency, DateTime.Now)
{
}
-
- public CacheDependency (string [] filenames, string [] cachekeys, CacheDependency dependency)
- : this (filenames, cachekeys, dependency, DateTime.MaxValue)
+
+ public CacheDependency (string[] filenames, string[] cachekeys, DateTime start): this (filenames, cachekeys, null, start)
{
}
-
- public CacheDependency (string [] filenames,
- string [] cachekeys,
- CacheDependency dependency,
- DateTime start)
+
+ public CacheDependency (string[] filenames, string[] cachekeys, CacheDependency dependency, DateTime start)
{
- Cache cache = HttpRuntime.Cache;
-
- if (filenames == null)
- filenames = noStrings;
-
- foreach (string file in filenames) {
- if (file == null)
- throw new ArgumentNullException ("filenames");
+ if (filenames != null) {
+ watchers = new FileSystemWatcher [filenames.Length];
+ for (int n=0; n<filenames.Length; n++) {
+ FileSystemWatcher watcher = new FileSystemWatcher ();
+ if (Directory.Exists (filenames [n])) {
+ watcher.Path = filenames [n];
+ } else {
+ string parentPath = Path.GetDirectoryName (filenames [n]);
+ if (parentPath != null && Directory.Exists (parentPath)) {
+ watcher.Path = parentPath;
+ watcher.Filter = Path.GetFileName (filenames [n]);
+ } else
+ continue;
+ }
+ watcher.NotifyFilter |= NotifyFilters.Size;
+ watcher.Created += new FileSystemEventHandler (OnChanged);
+ watcher.Changed += new FileSystemEventHandler (OnChanged);
+ watcher.Deleted += new FileSystemEventHandler (OnChanged);
+ watcher.Renamed += new RenamedEventHandler (OnChanged);
+ watcher.EnableRaisingEvents = true;
+ watchers [n] = watcher;
+ }
}
+ this.cachekeys = cachekeys;
+ this.dependency = dependency;
+ if (dependency != null)
+ dependency.DependencyChanged += new EventHandler (OnChildDependencyChanged);
+ this.start = start;
+
+#if NET_2_0
+ FinishInit ();
+#endif
+ }
- if (cachekeys == null)
- cachekeys = noStrings;
-
- int missing_keys = 0;
- foreach (string ck in cachekeys) {
- if (ck == null)
- throw new ArgumentNullException ("cachekeys");
- if (cache.GetEntry (ck) == null)
- missing_keys++;
+#if NET_2_0
+ public virtual string GetUniqueID ()
+ {
+ StringBuilder sb = new StringBuilder ();
+ lock (locker) {
+ if (watchers != null)
+ foreach (FileSystemWatcher fsw in watchers)
+ if (fsw != null && fsw.Path != null && fsw.Path.Length != 0)
+ sb.AppendFormat ("_{0}", fsw.Path);
}
- if (dependency == null)
- dependency = noDependency;
-
-
- this.changed = dependency.changed;
- if (changed == true)
- return;
-
- int nentries = cachekeys.Length + ((dependency.entries == null) ? 0 :
- dependency.entries.Length) - missing_keys;
-
- if (nentries != 0) {
- this.removedDelegate = new CacheItemRemovedCallback (CacheItemRemoved);
- this.entries = new CacheEntry [nentries];
-
- int i = 0;
- if (dependency.entries != null) {
- foreach (CacheEntry entry in dependency.entries) {
- entry._onRemoved += removedDelegate;
- entries [i++] = entry;
- }
- }
+ if (cachekeys != null)
+ foreach (string key in cachekeys)
+ sb.AppendFormat ("_{0}", key);
+ return sb.ToString ();
+ }
+#endif
+
+ void OnChanged (object sender, FileSystemEventArgs args)
+ {
+ OnDependencyChanged (sender, args);
+ }
- for (int c=0; c<cachekeys.Length; c++) {
- CacheEntry entry = cache.GetEntry (cachekeys [c]);
- if (entry == null)
- continue;
- entry._onRemoved += removedDelegate;
- entries [i++] = entry;
+ bool DoOnChanged ()
+ {
+ if (DateTime.Now < start)
+ return false;
+ hasChanged = true;
+#if NET_2_0
+ utcLastModified = DateTime.UtcNow;
+#endif
+ DisposeWatchers ();
+
+ if (cache != null)
+ cache.CheckExpiration ();
+
+ return true;
+ }
+
+ void DisposeWatchers ()
+ {
+ lock (locker) {
+ if (watchers != null) {
+ foreach (FileSystemWatcher w in watchers)
+ if (w != null)
+ w.Dispose ();
}
- }
-
- if (filenames.Length > 0) {
- watchers = new FileSystemWatcher [filenames.Length];
- for (int i=0; i<filenames.Length; i++)
- watchers [i] = CreateWatcher (filenames [i]);
+ watchers = null;
}
}
- private FileSystemWatcher CreateWatcher (string file)
+ public void Dispose ()
{
- FileSystemWatcher watcher = new FileSystemWatcher ();
-
- watcher.Path = Path.GetFullPath (Path.GetDirectoryName (file));
- watcher.Filter = Path.GetFileName (file);
-
- watcher.Changed += new FileSystemEventHandler (OnFileChanged);
- watcher.Created += new FileSystemEventHandler (OnFileChanged);
- watcher.Deleted += new FileSystemEventHandler (OnFileChanged);
-
- watcher.EnableRaisingEvents = true;
-
- return watcher;
+ DependencyDispose ();
}
- private void OnFileChanged (object sender, FileSystemEventArgs e)
+#if NET_2_0
+ internal virtual void DependencyDisposeInternal ()
{
- OnChanged (sender, e);
}
-
- void CacheItemRemoved (string key, object value, CacheItemRemovedReason reason)
+#endif
+
+#if NET_2_0
+ protected virtual
+#endif
+ void DependencyDispose ()
{
- OnChanged (this, EventArgs.Empty);
+#if NET_2_0
+ DependencyDisposeInternal ();
+#endif
+ DisposeWatchers ();
+ if (dependency != null)
+ dependency.DependencyChanged -= new EventHandler (OnChildDependencyChanged);
+ cache = null;
}
-
- void OnChanged (object sender, EventArgs args)
+
+ internal void SetCache (Cache c)
{
- if (changed || disposed)
- return;
+ cache = c;
+#if NET_2_0
+ used = c != null;
+#endif
+ }
+
+#if NET_2_0
+ protected internal void FinishInit ()
+ {
+ utcLastModified = DateTime.UtcNow;
+ }
- changed = true;
- if (Changed != null)
- Changed (this, new CacheDependencyChangedArgs (null));
+ internal bool IsUsed {
+ get { return used; }
}
- public void Dispose ()
+ internal DateTime Start {
+ get { return start; }
+ set { start = value; }
+ }
+
+ public DateTime UtcLastModified {
+ get {
+ return utcLastModified;
+ }
+ }
+
+ protected void SetUtcLastModified (DateTime utcLastModified)
{
- for (int i=0; i<watchers.Length; i++)
- watchers [i].Dispose ();
+ this.utcLastModified = utcLastModified;
}
+#endif
+
+ public bool HasChanged {
+ get {
+ if (hasChanged)
+ return true;
+
+ if (DateTime.Now < start)
+ return false;
+
+ if (cache != null && cachekeys != null) {
+ foreach (string key in cachekeys) {
+ if (cache.GetKeyLastChange (key) > start) {
+ hasChanged = true;
+ break;
+ }
+ }
+ }
+ if (hasChanged)
+ DisposeWatchers ();
- public bool HasChanged
+ return hasChanged;
+ }
+ }
+
+ void OnChildDependencyChanged (object o, EventArgs e)
{
- get { return changed; }
+ hasChanged = true;
+ OnDependencyChanged (o, e);
}
+
+ void OnDependencyChanged (object sender, EventArgs e)
+ {
+ if (!DoOnChanged ())
+ return;
+
+ if (DependencyChanged == null)
+ return;
- internal CacheEntry [] GetCacheEntries ()
+ foreach (EventHandler eh in DependencyChanged.GetInvocationList ())
+ eh (sender, e);
+ }
+
+#if NET_2_0
+ protected
+#else
+ internal
+#endif
+ void NotifyDependencyChanged (object sender, EventArgs e)
{
- return entries;
+ OnDependencyChanged (sender, e);
}
- internal event CacheDependencyChangedHandler Changed;
+ internal event EventHandler DependencyChanged;
}
}
-