public _CacheEntry(string path, DateTime lastWriteAtLoad, IContactProperties properties) { Assert.IsFalse(string.IsNullOrEmpty(path)); Assert.IsNotNull(properties); FilePath = path; LastModified = lastWriteAtLoad; Properties = properties; _timeToLive = _CachePolicy.TimeToLiveCount; // _weakProperties = null; }
public bool TryGetProperties(out IContactProperties properties) { properties = null; // File.GetLastWriteTime is documented as throwing UnauthorizedAccessException // when the file is missing. DateTime fileLastAccess; try { fileLastAccess = File.GetLastWriteTimeUtc(FilePath); } // UnauthorizedAccessException is thrown in the case of a missing file. catch (UnauthorizedAccessException) { // Can't get properties from a missing file. return false; } //catch (FileNotFoundException) { exceptionRaised = true; } //catch (DirectoryNotFoundException) { exceptionRaised = true; } catch (Exception e) { Assert.Fail("This path shouldn't have gotten into the dictionary.\n " + e.Message); throw; } // Can use this only if the file hasn't been modified since it was added. if (!fileLastAccess.Equals(LastModified)) { return false; } // The Properties reference may have been demoted to a WeakReference. // If it was but is still retrievable re-promote it to a strong reference. if (null == Properties) { Properties = _weakProperties.Target as IContactProperties; // If it's been collected we won't use it. if (null == Properties) { return false; } } Assert.IsNotNull(Properties); // If this is being requested then restore the maximum time-to-live counter. // Ensure most-recently used properties are prioritized. _timeToLive = _CachePolicy.TimeToLiveCount; properties = Properties; return true; }
public static WriteableContactProperties MakeWriteableCopy(IContactProperties properties) { Verify.IsNotNull(properties, "properties"); // Can use the internal constructor so we don't unnecessarily dupe the stream. return new WriteableContactProperties(properties.SaveToStream(), true); }
/// <summary>Try to create a contact from a file. Swallow reasonable exceptions.</summary> /// <param name="filePath">The file to load from</param> /// <param name="properties">The contact properties to return</param> /// <param name="lastModifiedUtc">Timestampe when the properties were last modified.</param> /// <returns></returns> private static bool _TryLoadPropertiesFromFile(string filePath, out IContactProperties properties, out DateTime lastModifiedUtc) { try { properties = _GetContactFromFile(filePath, out lastModifiedUtc); return true; } catch (FileNotFoundException) { } catch (InvalidDataException) { } catch (UnauthorizedAccessException) { } catch (Exception e) { // Really not expecting other failures here. Potentially causes problems. Assert.Fail(e.ToString()); throw; } lastModifiedUtc = default(DateTime); properties = null; return false; }
private bool _TryGetCachedFile(string normalizedPath, out IContactProperties properties) { Assert.AreEqual(normalizedPath, normalizedPath.ToUpperInvariant()); properties = null; _CacheEntry entry; if (!_fileCache.TryGetValue(normalizedPath, out entry)) { return false; } bool ret = entry.TryGetProperties(out properties); if (!ret) { _fileCache.Remove(normalizedPath); } return ret; }
/// <summary>Internal only constructor for Contact.</summary> /// <param name="manager"></param> /// <param name="properties"></param> /// <param name="fileName"></param> internal Contact(ContactManager manager, IContactProperties properties, string fileName) { Assert.IsNotNull(properties); Verify.IsNeitherNullNorEmpty(fileName, "fileName"); // Caller should have ensured this is canonicalized... Assert.AreEqual(fileName, IOPath.GetFullPath(fileName)); _manager = manager; _contactProperties = properties; _sharedProperties = true; _sourceHash = _contactProperties.StreamHash; _type = GetTypeFromExtension(fileName); Path = fileName; Id = ContactId.GetRuntimeId(ContactIds.Default.Value, Path); _originalName = Names.Default.FormattedName; }
/// <summary>Decrements the heart-beat timer for this.</summary> /// <returns> /// Whether this entry is still active. False implies it's completely dead. /// </returns> public bool DecrementTimer() { --_timeToLive; if (_timeToLive <= 0) { if (null != Properties) { // The entry hasn't been accessed for a fair amount of time. // Can't forcibly clean up the resources held by the properties, // but can demote the reference to be weak. _weakProperties = new WeakReference(Properties); Properties = null; } // If the garbage collector already cleared the properties then remove the entry. return _weakProperties.IsAlive; } Assert.IsNotNull(Properties); return true; }
/// <summary> /// Internal only constructor for ContactManager. /// </summary> /// <param name="manager">The associated ContactManager instance.</param> /// <param name="type">The type of the contact to create.</param> /// <remarks> /// This allows the contacts returned by IContactCollection to be managed by this class. /// The manager is associated with the contact, which allows for Save to be called without /// the contact being initially backed by a path. /// </remarks> internal Contact(ContactManager manager, ContactTypes type) { Verify.IsApartmentState(ApartmentState.STA, _exceptionStringBadThreadId); if (!_IsValidSingleContactType(type, false)) { throw new ArgumentException("The provided type must be of a legal single value (also not ContactTypes.None).", "type"); } _manager = manager; _contactProperties = new WriteableContactPropertiesAlias(); // The IContactProperties is disposable by this object. //_sharedProperties = false; // New contact, no file name associated with the Id. Id = ContactId.GetRuntimeId(ContactIds.Default.Value, null); // _path = null; _originalName = string.Empty; _type = type; // New contact, so no worries of conflicting changes on save. // _sourceHash = null; }
/// <summary> /// Load a contact from a stream. /// </summary> /// <param name="stream">The stream with the Contact contents to load.</param> /// <param name="type"> /// The type of the contact to create. ContactTypes.None is valid for this constructor. /// </param> /// <remarks> /// This is the only Contact constructor where ContactTypes.None is a valid type parameter. /// </remarks> public Contact(Stream stream, ContactTypes type) { Verify.IsNotNull(stream, "stream"); Verify.IsApartmentState(ApartmentState.STA, _exceptionStringBadThreadId); if (!_IsValidSingleContactType(type, true)) { throw new ArgumentException("ContactType must be a valid single value for this constructor (ContactTypes.None is OK).", "type"); } _type = type; // // Default values are implicitly set by the runtime (CodeAnalysis tools flag unnecessary default initializations). // // Loading a contact from a stream, so there's no path and the user can't commit changes directly. // _sourceHash = null; // _path = null; // Shouldn't need this either (only used for Commit) // _originalName = null; stream.Position = 0; // No reason to assume that because we're being loaded from a stream that this // is going to be modified. Go ahead and delay building the DOM. // CONSDIER: Adding a flag indicating intention to write. _contactProperties = new ReadonlyContactProperties(stream); // The IContactProperties is disposable by this object. //_sharedProperties = false; Id = ContactId.GetRuntimeId(ContactIds.Default.Value, null); }
private void _EnsureWriteableProperties() { if (_contactProperties.IsReadonly) { _contactProperties = WriteableContactPropertiesAlias.MakeWriteableCopy(_contactProperties); Assert.IsFalse(_contactProperties.IsReadonly); } }
/// <summary> /// Load a contact from a file. /// </summary> /// <param name="fileName">The file that contains the contact data to load.</param> /// <exception cref="InvalidDataException"> /// The specified file exists but doesn't doesn't represent a valid contact. /// </exception> /// <exception cref="FileNotFoundException"> /// The specified file couldn't be found. /// </exception> /// <exception cref="UnauthorizedAccessException"> /// The specified file couldn't be opened for an unknown reason. It may be that it's /// opened within incompatible sharing permissions. Retrying the operation at a later /// time may succeed. /// </exception> public Contact(string fileName) { Verify.IsNotNull(fileName, "fileName"); Verify.IsApartmentState(ApartmentState.STA, _exceptionStringBadThreadId); // make the path absolute. fileName = IOPath.GetFullPath(fileName); _contactProperties = ContactLoader.GetContactFromFile(fileName); _sharedProperties = true; // Only really need to compute the hash if we change the contact... _sourceHash = _contactProperties.StreamHash; Path = fileName; Id = ContactId.GetRuntimeId(ContactIds.Default.Value, Path); _originalName = Names.Default.FormattedName; _type = GetTypeFromExtension(fileName); }
/// <summary> /// Protected overload of Dispose that is standard in IDisposable patterns. /// </summary> /// <param name="disposing">Whether or not this is being called by Dispose, rather than by the finalizer.</param> /// <remarks> /// Overrides of this method should always call base.Dispose. /// </remarks> protected virtual void Dispose(bool disposing) { if (disposing) { // Only dispose of the IContactProperties if it's not potentially shared with others. // Otherwise set it to null and let the GC deal with it as it sees fit. if (!_sharedProperties) { var disposable = _contactProperties as IDisposable; Utility.SafeDispose(ref disposable); } _contactProperties = null; } }