Move probing assembly folder behavior in separate class

The behavior of the "assembly load probing folder" is really
a separate concern from managing the list of loaded extesions.

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-06-16 14:35:13 -07:00
parent 2705aff234
commit ed410cba61
8 changed files with 135 additions and 94 deletions

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Linq;
using Orchard.Caching;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.Dependencies;
@@ -14,11 +13,13 @@ namespace Orchard.Environment.Extensions.Loaders {
/// </summary>
public class PrecompiledExtensionLoader : ExtensionLoaderBase {
private readonly IDependenciesFolder _dependenciesFolder;
private readonly IAssemblyProbingFolder _assemblyProbingFolder;
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IVirtualPathMonitor _virtualPathMonitor;
public PrecompiledExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider, IVirtualPathMonitor virtualPathMonitor) {
public PrecompiledExtensionLoader(IDependenciesFolder dependenciesFolder, IAssemblyProbingFolder assemblyProbingFolder, IVirtualPathProvider virtualPathProvider, IVirtualPathMonitor virtualPathMonitor) {
_dependenciesFolder = dependenciesFolder;
_assemblyProbingFolder = assemblyProbingFolder;
_virtualPathProvider = virtualPathProvider;
_virtualPathMonitor = virtualPathMonitor;
Logger = NullLogger.Instance;
@@ -33,7 +34,7 @@ namespace Orchard.Environment.Extensions.Loaders {
}
public override void ExtensionRemoved(ExtensionLoadingContext ctx, DependencyDescriptor dependency) {
var assemblyFileName = _dependenciesFolder.GetProbingAssemblyPhysicalFileName(dependency.Name);
var assemblyFileName = _assemblyProbingFolder.GetAssemblyPhysicalFileName(dependency.Name);
if (File.Exists(assemblyFileName)) {
ctx.FilesToDelete.Add(assemblyFileName);
@@ -47,7 +48,7 @@ namespace Orchard.Environment.Extensions.Loaders {
public override void ExtensionActivated(ExtensionLoadingContext ctx, bool isNewExtension, ExtensionDescriptor extension) {
string sourceFileName = _virtualPathProvider.MapPath(GetAssemblyPath(extension));
string destinationFileName = _dependenciesFolder.GetProbingAssemblyPhysicalFileName(extension.Name);
string destinationFileName = _assemblyProbingFolder.GetAssemblyPhysicalFileName(extension.Name);
if (FileIsNewer(sourceFileName, destinationFileName)) {
ctx.FilesToCopy.Add(sourceFileName, destinationFileName);
// We need to restart the appDomain if the assembly is loaded
@@ -59,7 +60,7 @@ namespace Orchard.Environment.Extensions.Loaders {
}
public override void ExtensionDeactivated(ExtensionLoadingContext ctx, bool isNewExtension, ExtensionDescriptor extension) {
var assemblyFileName = _dependenciesFolder.GetProbingAssemblyPhysicalFileName(extension.Name);
var assemblyFileName = _assemblyProbingFolder.GetAssemblyPhysicalFileName(extension.Name);
if (File.Exists(assemblyFileName)) {
ctx.FilesToDelete.Add(assemblyFileName);
// We need to restart the appDomain if the assembly is loaded
@@ -95,14 +96,14 @@ namespace Orchard.Environment.Extensions.Loaders {
var dependency = _dependenciesFolder.GetDescriptor(descriptor.Name);
if (dependency != null && dependency.LoaderName == this.Name) {
var assembly = _dependenciesFolder.GetProbingAssembly(descriptor.Name);
var assembly = _assemblyProbingFolder.LoadAssembly(descriptor.Name);
if (assembly == null)
return null;
return new ExtensionEntry {
Descriptor = descriptor,
Assembly = assembly.Assembly(),
ExportedTypes = assembly.Assembly().GetExportedTypes()
Assembly = assembly,
ExportedTypes = assembly.GetExportedTypes()
};
}
return null;

View File

@@ -1,10 +1,6 @@
using System;
using System.IO;
using System.Linq;
using Orchard.Caching;
using System.IO;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.Dependencies;
using Orchard.FileSystems.VirtualPath;
using Orchard.Logging;
namespace Orchard.Environment.Extensions.Loaders {
@@ -14,11 +10,11 @@ namespace Orchard.Environment.Extensions.Loaders {
/// </summary>
public class ProbingExtensionLoader : ExtensionLoaderBase {
private readonly IDependenciesFolder _dependenciesFolder;
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IAssemblyProbingFolder _assemblyProbingFolder;
public ProbingExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider) {
public ProbingExtensionLoader(IDependenciesFolder dependenciesFolder, IAssemblyProbingFolder assemblyProbingFolder) {
_dependenciesFolder = dependenciesFolder;
_virtualPathProvider = virtualPathProvider;
_assemblyProbingFolder = assemblyProbingFolder;
Logger = NullLogger.Instance;
}
@@ -31,7 +27,7 @@ namespace Orchard.Environment.Extensions.Loaders {
}
public override void ExtensionRemoved(ExtensionLoadingContext ctx, DependencyDescriptor dependency) {
var assemblyFileName = _dependenciesFolder.GetProbingAssemblyPhysicalFileName(dependency.Name);
var assemblyFileName = _assemblyProbingFolder.GetAssemblyPhysicalFileName(dependency.Name);
if (File.Exists(assemblyFileName)) {
ctx.FilesToDelete.Add(assemblyFileName);
// We need to restart the appDomain if the assembly is loaded
@@ -43,7 +39,7 @@ namespace Orchard.Environment.Extensions.Loaders {
}
public override void ExtensionDeactivated(ExtensionLoadingContext ctx, bool isNewExtension, ExtensionDescriptor extension) {
var assemblyFileName = _dependenciesFolder.GetProbingAssemblyPhysicalFileName(extension.Name);
var assemblyFileName = _assemblyProbingFolder.GetAssemblyPhysicalFileName(extension.Name);
if (File.Exists(assemblyFileName)) {
ctx.FilesToDelete.Add(assemblyFileName);
// We need to restart the appDomain if the assembly is loaded
@@ -55,8 +51,7 @@ namespace Orchard.Environment.Extensions.Loaders {
}
public override ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) {
var probingAssembly = _dependenciesFolder.GetProbingAssembly(descriptor.Name);
if (probingAssembly == null)
if (!_assemblyProbingFolder.HasAssembly(descriptor.Name))
return null;
var desc = _dependenciesFolder.GetDescriptor(descriptor.Name);
@@ -65,7 +60,7 @@ namespace Orchard.Environment.Extensions.Loaders {
return new ExtensionProbeEntry {
Descriptor = descriptor,
LastModificationTimeUtc = probingAssembly.LastWriteTimeUtc(),
LastModificationTimeUtc = _assemblyProbingFolder.GetAssemblyDateTimeUtc(descriptor.Name),
Loader = this,
VirtualPath = desc.VirtualPath
};
@@ -75,14 +70,14 @@ namespace Orchard.Environment.Extensions.Loaders {
var dependency = _dependenciesFolder.GetDescriptor(descriptor.Name);
if (dependency != null && dependency.LoaderName == this.Name) {
var assembly = _dependenciesFolder.GetProbingAssembly(descriptor.Name);
var assembly = _assemblyProbingFolder.LoadAssembly(descriptor.Name);
if (assembly == null)
return null;
return new ExtensionEntry {
Descriptor = descriptor,
Assembly = assembly.Assembly(),
ExportedTypes = assembly.Assembly().GetExportedTypes()
Assembly = assembly,
ExportedTypes = assembly.GetExportedTypes()
};
}
return null;

View File

@@ -42,6 +42,7 @@ namespace Orchard.Environment {
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);
RegisterVolatileProvider<Clock, IClock>(builder);
RegisterVolatileProvider<DefaultDependenciesFolder, IDependenciesFolder>(builder);
RegisterVolatileProvider<DefaultAssemblyProbingFolder, IAssemblyProbingFolder>(builder);
RegisterVolatileProvider<DefaultVirtualPathMonitor, IVirtualPathMonitor>(builder);
RegisterVolatileProvider<DefaultVirtualPathProvider, IVirtualPathProvider>(builder);

View File

@@ -0,0 +1,41 @@
using System;
using System.IO;
using System.Reflection;
using Orchard.FileSystems.AppData;
namespace Orchard.FileSystems.Dependencies {
public class DefaultAssemblyProbingFolder : IAssemblyProbingFolder {
private const string BasePath = "Dependencies";
private readonly IAppDataFolder _appDataFolder;
public DefaultAssemblyProbingFolder(IAppDataFolder appDataFolder) {
_appDataFolder = appDataFolder;
}
public bool HasAssembly(string moduleName) {
var path = PrecompiledAssemblyPath(moduleName);
return _appDataFolder.FileExists(path);
}
public DateTime GetAssemblyDateTimeUtc(string moduleName) {
var path = PrecompiledAssemblyPath(moduleName);
return File.GetLastWriteTimeUtc(_appDataFolder.MapPath(path));
}
public Assembly LoadAssembly(string moduleName) {
var path = PrecompiledAssemblyPath(moduleName);
if (!_appDataFolder.FileExists(path))
return null;
return Assembly.Load(moduleName);
}
public string GetAssemblyPhysicalFileName(string moduleName) {
return _appDataFolder.MapPath(PrecompiledAssemblyPath(moduleName));
}
private string PrecompiledAssemblyPath(string moduleName) {
return _appDataFolder.Combine(BasePath, moduleName + ".dll");
}
}
}

View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Orchard.Caching;
using Orchard.FileSystems.AppData;
@@ -31,74 +29,31 @@ namespace Orchard.FileSystems.Dependencies {
}
}
private IEnumerable<DependencyDescriptor> Descriptors {
get {
return _cacheManager.Get(PersistencePath,
ctx => {
_appDataFolder.CreateDirectory(BasePath);
ctx.Monitor(_appDataFolder.WhenPathChanges(ctx.Key));
ctx.Monitor(_writeThroughToken);
_appDataFolder.CreateDirectory(BasePath);
return ReadDependencies(ctx.Key).ToList();
});
}
public DependencyDescriptor GetDescriptor(string moduleName) {
return LoadDescriptors().SingleOrDefault(d => d.Name == moduleName);
}
public IEnumerable<DependencyDescriptor> LoadDescriptors() {
return Descriptors;
return _cacheManager.Get(PersistencePath,
ctx => {
_appDataFolder.CreateDirectory(BasePath);
ctx.Monitor(_appDataFolder.WhenPathChanges(ctx.Key));
ctx.Monitor(_writeThroughToken);
_appDataFolder.CreateDirectory(BasePath);
return ReadDependencies(ctx.Key).ToList();
});
}
public void StoreDescriptors(IEnumerable<DependencyDescriptor> dependencyDescriptors) {
var existingDescriptors = this.Descriptors.OrderBy(d => d.Name);
var existingDescriptors = LoadDescriptors().OrderBy(d => d.Name);
var newDescriptors = dependencyDescriptors.OrderBy(d => d.Name);
if (!newDescriptors.SequenceEqual(existingDescriptors, new DependencyDescriptorComparer())) {
WriteDependencies(PersistencePath, dependencyDescriptors);
}
}
private class DependencyDescriptorComparer : EqualityComparer<DependencyDescriptor> {
public override bool Equals(DependencyDescriptor x, DependencyDescriptor y) {
return
StringComparer.OrdinalIgnoreCase.Equals(x.Name, y.Name) &&
StringComparer.OrdinalIgnoreCase.Equals(x.LoaderName, y.LoaderName) &&
StringComparer.OrdinalIgnoreCase.Equals(x.VirtualPath, y.VirtualPath);
}
public override int GetHashCode(DependencyDescriptor obj) {
return
StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name) ^
StringComparer.OrdinalIgnoreCase.GetHashCode(obj.LoaderName) ^
StringComparer.OrdinalIgnoreCase.GetHashCode(obj.VirtualPath);
}
}
public DependencyDescriptor GetDescriptor(string moduleName) {
return Descriptors.SingleOrDefault(d => d.Name == moduleName);
}
public ProbingAssembly GetProbingAssembly(string moduleName) {
var path = PrecompiledAssemblyPath(moduleName);
if (!_appDataFolder.FileExists(path))
return null;
return new ProbingAssembly {
Path = path,
Assembly = () => Assembly.Load(moduleName),
LastWriteTimeUtc = () => File.GetLastWriteTimeUtc(_appDataFolder.MapPath(path)),
};
}
public string GetProbingAssemblyPhysicalFileName(string moduleName) {
return _appDataFolder.MapPath(PrecompiledAssemblyPath(moduleName));
}
private string PrecompiledAssemblyPath(string moduleName) {
return _appDataFolder.Combine(BasePath, moduleName + ".dll");
}
private IEnumerable<DependencyDescriptor> ReadDependencies(string persistancePath) {
Func<string, XName> ns = (name => XName.Get(name));
Func<XElement, string, string> elem = (e, name) => e.Element(ns(name)).Value;
@@ -142,5 +97,22 @@ namespace Orchard.FileSystems.Dependencies {
private class InvalidationToken : IVolatileToken {
public bool IsCurrent { get; set; }
}
private class DependencyDescriptorComparer : EqualityComparer<DependencyDescriptor> {
public override bool Equals(DependencyDescriptor x, DependencyDescriptor y) {
return
StringComparer.OrdinalIgnoreCase.Equals(x.Name, y.Name) &&
StringComparer.OrdinalIgnoreCase.Equals(x.LoaderName, y.LoaderName) &&
StringComparer.OrdinalIgnoreCase.Equals(x.VirtualPath, y.VirtualPath);
}
public override int GetHashCode(DependencyDescriptor obj) {
return
StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name) ^
StringComparer.OrdinalIgnoreCase.GetHashCode(obj.LoaderName) ^
StringComparer.OrdinalIgnoreCase.GetHashCode(obj.VirtualPath);
}
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Reflection;
using Orchard.Caching;
namespace Orchard.FileSystems.Dependencies {
/// <summary>
/// Abstraction over the folder configued in web.config as an additional
/// location to load assemblies from. This assumes a local physical file system,
/// since Orchard will need to store assembly files locally.
/// </summary>
public interface IAssemblyProbingFolder : IVolatileProvider {
/// <summary>
/// Return "true" if the assembly corresponding to "moduleName" is
/// present in the folder.
/// </summary>
bool HasAssembly(string moduleName);
/// <summary>
/// Return the last modification date of the assembly corresponding
/// to "moduleName". The assembly must be exist on disk, otherwise an
/// exception is thrown.
/// </summary>
DateTime GetAssemblyDateTimeUtc(string moduleName);
/// <summary>
/// Load the assembly corresponding to "moduleName" if the assembly file
/// is present in the folder.
/// </summary>
Assembly LoadAssembly(string moduleName);
/// <summary>
/// Return the physical location where to store the assembly
/// corresponding to "moduleName". This will return a correct path
/// even if the assembly is not currently stored in that location.
/// This method can be used to answer the question "Where would the assembly
/// for module "moduleName" be stored if it exsisted?"
/// </summary>
string GetAssemblyPhysicalFileName(string moduleName);
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Collections.Generic;
using Orchard.Caching;
namespace Orchard.FileSystems.Dependencies {
@@ -10,18 +8,9 @@ namespace Orchard.FileSystems.Dependencies {
public string VirtualPath { get; set; }
}
public class ProbingAssembly {
public string Path { get; set; }
public Func<DateTime> LastWriteTimeUtc { get; set; }
public Func<Assembly> Assembly { get; set; }
}
public interface IDependenciesFolder : IVolatileProvider {
DependencyDescriptor GetDescriptor(string moduleName);
IEnumerable<DependencyDescriptor> LoadDescriptors();
void StoreDescriptors(IEnumerable<DependencyDescriptor> dependencyDescriptors);
ProbingAssembly GetProbingAssembly(string moduleName);
string GetProbingAssemblyPhysicalFileName(string moduleName);
}
}

View File

@@ -358,7 +358,9 @@
<Compile Include="Environment\Extensions\IExtensionLoaderCoordinator.cs" />
<Compile Include="Environment\Extensions\Loaders\ExtensionLoaderBase.cs" />
<Compile Include="FileSystems\AppData\IAppDataFolderRoot.cs" />
<Compile Include="FileSystems\Dependencies\DefaultAssemblyProbingFolder.cs" />
<Compile Include="FileSystems\Dependencies\DefaultDependenciesFolder.cs" />
<Compile Include="FileSystems\Dependencies\IAssenblyProbyFolder.cs" />
<Compile Include="FileSystems\VirtualPath\DefaultVirtualPathMonitor.cs" />
<Compile Include="FileSystems\VirtualPath\DefaultVirtualPathProvider.cs" />
<Compile Include="FileSystems\VirtualPath\ICustomVirtualPathProvider.cs" />