Incremental work towards cache/volatile system

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-05-14 22:30:16 -07:00
parent fba838f366
commit c138cc996d
40 changed files with 396 additions and 217 deletions

View File

@@ -18,7 +18,18 @@ namespace Orchard.Profile.Tests {
[Given(@"I am logged in")] [Given(@"I am logged in")]
public void GivenIAmLoggedIn() { public void GivenIAmLoggedIn() {
DoRequest("/Users/Account/LogOn", "userNameOrEmail=admin&password=profiling-secret&rememberMe=false"); DoRequest("/Users/Account/LogOn");
const string requestVerificationTokenName = "__RequestVerificationToken";
const string valueMarker = "value=\"";
var tokenIndex = _text.IndexOf(requestVerificationTokenName);
var valueIndex = _text.IndexOf(valueMarker, tokenIndex);
var valueStart = valueIndex + valueMarker.Length;
var valueEnd = _text.IndexOf("\"", valueStart);
var requestVerificationTokenValue = _text.Substring(valueStart, valueEnd - valueStart);
DoRequest("/Users/Account/LogOn", "userNameOrEmail=admin&password=profiling-secret&rememberMe=false&" + requestVerificationTokenName + "=" + requestVerificationTokenValue);
} }
[When(@"I go to ""(.*)""")] [When(@"I go to ""(.*)""")]

View File

@@ -3,6 +3,12 @@
As a developer As a developer
I want to generate a fixed number of repeatable requests I want to generate a fixed number of repeatable requests
Scenario: Warmup
Given I am logged in
When I go to "/admin"
When I go to "/blog0"
When I go to "/"
Scenario: Dashboard Scenario: Dashboard
Given I am logged in Given I am logged in
When I go to "/admin" 40 times When I go to "/admin" 40 times

View File

@@ -2,7 +2,7 @@
// <auto-generated> // <auto-generated>
// This code was generated by SpecFlow (http://www.specflow.org/). // This code was generated by SpecFlow (http://www.specflow.org/).
// SpecFlow Version:1.2.0.0 // SpecFlow Version:1.2.0.0
// Runtime Version:2.0.50727.3603 // Runtime Version:2.0.50727.4927
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -51,15 +51,34 @@ namespace Orchard.Profile.Tests
} }
[NUnit.Framework.TestAttribute()] [NUnit.Framework.TestAttribute()]
[NUnit.Framework.DescriptionAttribute("Dashboard")] [NUnit.Framework.DescriptionAttribute("Warmup")]
public virtual void Dashboard() public virtual void Warmup()
{ {
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Dashboard", ((string[])(null))); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Warmup", ((string[])(null)));
#line 6 #line 6
this.ScenarioSetup(scenarioInfo); this.ScenarioSetup(scenarioInfo);
#line 7 #line 7
testRunner.Given("I am logged in"); testRunner.Given("I am logged in");
#line 8 #line 8
testRunner.When("I go to \"/admin\"");
#line 9
testRunner.When("I go to \"/blog0\"");
#line 10
testRunner.When("I go to \"/\"");
#line hidden
testRunner.CollectScenarioErrors();
}
[NUnit.Framework.TestAttribute()]
[NUnit.Framework.DescriptionAttribute("Dashboard")]
public virtual void Dashboard()
{
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Dashboard", ((string[])(null)));
#line 12
this.ScenarioSetup(scenarioInfo);
#line 13
testRunner.Given("I am logged in");
#line 14
testRunner.When("I go to \"/admin\" 40 times"); testRunner.When("I go to \"/admin\" 40 times");
#line hidden #line hidden
testRunner.CollectScenarioErrors(); testRunner.CollectScenarioErrors();
@@ -70,19 +89,19 @@ this.ScenarioSetup(scenarioInfo);
public virtual void HittingBlogs() public virtual void HittingBlogs()
{ {
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hitting blogs", ((string[])(null))); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hitting blogs", ((string[])(null)));
#line 10
this.ScenarioSetup(scenarioInfo);
#line 11
testRunner.Given("I am logged in");
#line 12
testRunner.When("I go to \"/blog0\" 10 times");
#line 13
testRunner.When("I go to \"/blog1\" 10 times");
#line 14
testRunner.When("I go to \"/blog2\" 10 times");
#line 15
testRunner.When("I go to \"/blog3\" 10 times");
#line 16 #line 16
this.ScenarioSetup(scenarioInfo);
#line 17
testRunner.Given("I am logged in");
#line 18
testRunner.When("I go to \"/blog0\" 10 times");
#line 19
testRunner.When("I go to \"/blog1\" 10 times");
#line 20
testRunner.When("I go to \"/blog2\" 10 times");
#line 21
testRunner.When("I go to \"/blog3\" 10 times");
#line 22
testRunner.When("I go to \"/blog4\" 10 times"); testRunner.When("I go to \"/blog4\" 10 times");
#line hidden #line hidden
testRunner.CollectScenarioErrors(); testRunner.CollectScenarioErrors();
@@ -93,11 +112,11 @@ this.ScenarioSetup(scenarioInfo);
public virtual void HittingHomePage() public virtual void HittingHomePage()
{ {
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hitting home page", ((string[])(null))); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hitting home page", ((string[])(null)));
#line 18 #line 24
this.ScenarioSetup(scenarioInfo); this.ScenarioSetup(scenarioInfo);
#line 19 #line 25
testRunner.Given("I am logged in"); testRunner.Given("I am logged in");
#line 20 #line 26
testRunner.When("I go to \"/\" 40 times"); testRunner.When("I go to \"/\" 40 times");
#line hidden #line hidden
testRunner.CollectScenarioErrors(); testRunner.CollectScenarioErrors();

View File

@@ -1,6 +1,3 @@
help commands setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLite /EnabledFeatures:Orchard.Framework,Common,Dashboard,Feeds,HomePage,Navigation,Scheduling,Settings,XmlRpc,Orchard.Users,Orchard.Roles,TinyMce,Orchard.Modules,Orchard.Themes,Orchard.MultiTenancy,Orchard.Pages,Orchard.Blogs,Orchard.Comments,Futures.Widgets,Orchard.Media,Orchard.Tags,Orchard.DevTools
setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLite /EnabledFeatures:Orchard.Framework,Common,Dashboard,Feeds,HomePage,Navigation,Scheduling,Settings,XmlRpc,Orchard.Users,Orchard.Roles,TinyMce,Orchard.Modules,Orchard.Themes,Orchard.MultiTenancy,Orchard.Pages,Orchard.Blogs,Orchard.Comments,Futures.Widgets,Orchard.Media,Orchard.Tags,Orchard.DevTools
help commands
tenant list
feature list
add profiling data add profiling data
feature disable Orchard.DevTools

View File

@@ -2,6 +2,7 @@
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Environment.FileSystems;
namespace Orchard.Tests.Environment.Configuration { namespace Orchard.Tests.Environment.Configuration {
[TestFixture] [TestFixture]

View File

@@ -15,6 +15,7 @@ using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Folders; using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
using Orchard.Environment.FileSystems;
using Orchard.Environment.ShellBuilders; using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Topology; using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models; using Orchard.Environment.Topology.Models;

View File

@@ -49,7 +49,7 @@ namespace Orchard.Tests.Environment.Extensions {
[Test] [Test]
public void NamesFromFoldersWithModuleTxtShouldBeListed() { public void NamesFromFoldersWithModuleTxtShouldBeListed() {
var folders = new ModuleFolders(new[] { _tempFolderName }); var folders = new ModuleFolders(new[] { _tempFolderName },null,null);
var names = folders.ListNames(); var names = folders.ListNames();
Assert.That(names.Count(), Is.EqualTo(2)); Assert.That(names.Count(), Is.EqualTo(2));
Assert.That(names, Has.Some.EqualTo("Sample1")); Assert.That(names, Has.Some.EqualTo("Sample1"));
@@ -58,7 +58,7 @@ namespace Orchard.Tests.Environment.Extensions {
[Test] [Test]
public void ModuleTxtShouldBeParsedAndReturnedAsYamlDocument() { public void ModuleTxtShouldBeParsedAndReturnedAsYamlDocument() {
var folders = new ModuleFolders(new[] { _tempFolderName }); var folders = new ModuleFolders(new[] { _tempFolderName },null,null);
var sample1 = folders.ParseManifest("Sample1"); var sample1 = folders.ParseManifest("Sample1");
var mapping = (Mapping)sample1.YamlDocument.Root; var mapping = (Mapping)sample1.YamlDocument.Root;
var entities = mapping.Entities var entities = mapping.Entities

View File

@@ -51,6 +51,10 @@ namespace Orchard.Tests.Environment.Extensions {
} }
return null; return null;
} }
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
throw new NotImplementedException();
}
} }
public class StubLoaders : IExtensionLoader { public class StubLoaders : IExtensionLoader {

View File

@@ -4,6 +4,7 @@ using System.Xml;
using Autofac; using Autofac;
using NUnit.Framework; using NUnit.Framework;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Environment.FileSystems;
using Orchard.Environment.Topology; using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models; using Orchard.Environment.Topology.Models;

View File

@@ -56,6 +56,14 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\fluentnhibernate\FluentNHibernate.dll</HintPath> <HintPath>..\..\lib\fluentnhibernate\FluentNHibernate.dll</HintPath>
</Reference> </Reference>
<Reference Include="Machine.Migrations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c474de7a495cff1, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.dll</HintPath>
</Reference>
<Reference Include="Machine.Migrations.NHibernate, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.NHibernate.dll</HintPath>
</Reference>
<Reference Include="Moq, Version=4.0.812.4, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL"> <Reference Include="Moq, Version=4.0.812.4, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\moq\Moq.dll</HintPath> <HintPath>..\..\lib\moq\Moq.dll</HintPath>

View File

@@ -73,7 +73,6 @@
<Compile Include="Models\ShowDebugLink.cs" /> <Compile Include="Models\ShowDebugLink.cs" />
<Compile Include="Models\Simple.cs" /> <Compile Include="Models\Simple.cs" />
<Compile Include="Permissions.cs" /> <Compile Include="Permissions.cs" />
<Compile Include="Profiler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewModels\ContentIndexViewModel.cs" /> <Compile Include="ViewModels\ContentIndexViewModel.cs" />
<Compile Include="ViewModels\ContentDetailsViewModel.cs" /> <Compile Include="ViewModels\ContentDetailsViewModel.cs" />

View File

@@ -1,13 +0,0 @@
using Orchard.Environment;
namespace Orchard.DevTools {
public class Profiler : IOrchardShellEvents {
public void Activated() {
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();
}
public void Terminating() {
}
}
}

View File

@@ -8,8 +8,8 @@ using Orchard.Core.Navigation.Models;
using Orchard.Core.Settings.Models; using Orchard.Core.Settings.Models;
using Orchard.Data; using Orchard.Data;
using Orchard.Environment; using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.FileSystems;
using Orchard.Environment.ShellBuilders; using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Topology; using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models; using Orchard.Environment.Topology.Models;

View File

@@ -57,7 +57,7 @@ namespace Orchard.Users.Controllers {
[HttpPost] [HttpPost]
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameter type as Controller.Redirect()")] Justification = "Needs to take same parameter type as Controller.Redirect()")]
public ActionResult LogOn(string userNameOrEmail, string password, bool rememberMe) { public ActionResult LogOn(string userNameOrEmail, string password, bool rememberMe, string returnUrl) {
var user = ValidateLogOn(userNameOrEmail, password); var user = ValidateLogOn(userNameOrEmail, password);
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
return View("LogOn", new LogOnViewModel {Title = "Log On"}); return View("LogOn", new LogOnViewModel {Title = "Log On"});
@@ -65,13 +65,19 @@ namespace Orchard.Users.Controllers {
_authenticationService.SignIn(user, rememberMe); _authenticationService.SignIn(user, rememberMe);
return this.ReturnUrlRedirect(); if (string.IsNullOrEmpty(returnUrl))
return new RedirectResult("~/");
return new RedirectResult(returnUrl);
} }
public ActionResult LogOff() { public ActionResult LogOff(string returnUrl) {
_authenticationService.SignOut(); _authenticationService.SignOut();
return this.ReturnUrlRedirect(); if (string.IsNullOrEmpty(returnUrl))
return new RedirectResult("~/");
return new RedirectResult(returnUrl);
} }
int MinPasswordLength { int MinPasswordLength {

View File

@@ -393,7 +393,7 @@
<WebProjectProperties> <WebProjectProperties>
<UseIIS>False</UseIIS> <UseIIS>False</UseIIS>
<AutoAssignPort>False</AutoAssignPort> <AutoAssignPort>False</AutoAssignPort>
<DevelopmentServerPort>30320</DevelopmentServerPort> <DevelopmentServerPort>80</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath> <DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl> <IISUrl>
</IISUrl> </IISUrl>

View File

@@ -1,4 +1,14 @@
namespace Orchard.Caching { using System;
public class AcquireContext { using Orchard.Caching.Providers;
namespace Orchard.Caching {
public class AcquireContext<TKey> {
public AcquireContext(TKey key, Action<IVolatileSignal> monitor) {
Key = key;
IsInvalid = monitor;
}
public TKey Key { get; private set; }
public Action<IVolatileSignal> IsInvalid { get; private set; }
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Caching.Providers;
namespace Orchard.Caching { namespace Orchard.Caching {
public class Cache<TKey, TResult> : ICache<TKey, TResult> { public class Cache<TKey, TResult> : ICache<TKey, TResult> {
@@ -9,22 +10,21 @@ namespace Orchard.Caching {
_entries = new Dictionary<TKey, CacheEntry>(); _entries = new Dictionary<TKey, CacheEntry>();
} }
#region Implementation of ICache<TKey,TResult> public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
public TResult Get(TKey key, Func<AcquireContext, TResult> acquire) {
CacheEntry entry; CacheEntry entry;
if (!_entries.TryGetValue(key, out entry)) { if (!_entries.TryGetValue(key, out entry)) {
AcquireContext context = new AcquireContext(); entry = new CacheEntry { VolatileItems = new List<IVolatileSignal>() };
entry = new CacheEntry {Result = acquire(context)};
var context = new AcquireContext<TKey>(key, volatileItem => entry.VolatileItems.Add(volatileItem));
entry.Result = acquire(context);
_entries.Add(key, entry); _entries.Add(key, entry);
} }
return entry.Result; return entry.Result;
} }
#endregion private class CacheEntry {
public class CacheEntry {
public TResult Result { get; set; } public TResult Result { get; set; }
public IList<IVolatileSignal> VolatileItems { get; set; }
} }
} }

View File

@@ -12,7 +12,7 @@ namespace Orchard.Caching {
#region Implementation of ICacheManager #region Implementation of ICacheManager
public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext, TResult> acquire) { public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
return GetCache<TKey, TResult>().Get(key, acquire); return GetCache<TKey, TResult>().Get(key, acquire);
} }

View File

@@ -2,6 +2,6 @@
namespace Orchard.Caching { namespace Orchard.Caching {
public interface ICache<TKey, TResult> { public interface ICache<TKey, TResult> {
TResult Get(TKey key, Func<AcquireContext, TResult> acquire); TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire);
} }
} }

View File

@@ -2,7 +2,7 @@
namespace Orchard.Caching { namespace Orchard.Caching {
public interface ICacheManager : ISingletonDependency { public interface ICacheManager : ISingletonDependency {
TResult Get<TKey, TResult>(TKey key, Func<AcquireContext, TResult> acquire); TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire);
ICache<TKey, TResult> GetCache<TKey, TResult>(); ICache<TKey, TResult> GetCache<TKey, TResult>();
} }
} }

View File

@@ -0,0 +1,5 @@
namespace Orchard.Caching.Providers {
public interface IVolatileProvider : IDependency {
void Enlist(IVolatileSink sink);
}
}

View File

@@ -0,0 +1,5 @@
namespace Orchard.Caching.Providers {
public interface IVolatileSignal {
IVolatileProvider Provider { get; set; }
}
}

View File

@@ -0,0 +1,5 @@
namespace Orchard.Caching.Providers {
public interface IVolatileSink {
}
}

View File

@@ -3,6 +3,7 @@ using System.IO;
using NHibernate; using NHibernate;
using Orchard.Data.Builders; using Orchard.Data.Builders;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Environment.FileSystems;
using Orchard.Environment.Topology; using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models; using Orchard.Environment.Topology.Models;
using Orchard.Logging; using Orchard.Logging;

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Yaml.Serialization; using System.Yaml.Serialization;
using Orchard.Environment.FileSystems;
using Orchard.Localization; using Orchard.Localization;
namespace Orchard.Environment.Configuration { namespace Orchard.Environment.Configuration {

View File

@@ -34,13 +34,7 @@ namespace Orchard.Environment.Extensions {
// This method does not load extension types, simply parses extension manifests from // This method does not load extension types, simply parses extension manifests from
// the filesystem. // the filesystem.
public IEnumerable<ExtensionDescriptor> AvailableExtensions() { public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
var availableExtensions = new List<ExtensionDescriptor>(); return _folders.SelectMany(folder=>folder.AvailableExtensions());
foreach (var folder in _folders) {
foreach (var name in folder.ListNames()) {
availableExtensions.Add(GetDescriptorForExtension(name, folder));
}
}
return availableExtensions;
} }
public IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors) { public IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors) {
@@ -57,65 +51,6 @@ namespace Orchard.Environment.Extensions {
return _activeExtensions; return _activeExtensions;
} }
private static ExtensionDescriptor GetDescriptorForExtension(string name, IExtensionFolders folder) {
string extensionType = folder is ThemeFolders ? "Theme" : "Module";
var parseResult = folder.ParseManifest(name);
var mapping = (Mapping)parseResult.YamlDocument.Root;
var fields = mapping.Entities
.Where(x => x.Key is Scalar)
.ToDictionary(x => ((Scalar)x.Key).Text, x => x.Value);
var extensionDescriptor = new ExtensionDescriptor {
Location = parseResult.Location,
Name = name,
ExtensionType = extensionType,
DisplayName = GetValue(fields, "name") ?? name,
Description = GetValue(fields, "description"),
Version = GetValue(fields, "version"),
OrchardVersion = GetValue(fields, "orchardversion"),
Author = GetValue(fields, "author"),
WebSite = GetValue(fields, "website"),
Tags = GetValue(fields, "tags"),
AntiForgery = GetValue(fields, "antiforgery"),
};
extensionDescriptor.Features = GetFeaturesForExtension(GetMapping(fields, "features"), extensionDescriptor);
return extensionDescriptor;
}
private static IEnumerable<FeatureDescriptor> GetFeaturesForExtension(Mapping features, ExtensionDescriptor extensionDescriptor) {
List<FeatureDescriptor> featureDescriptors = new List<FeatureDescriptor>();
if (features != null) {
foreach (var entity in features.Entities) {
FeatureDescriptor featureDescriptor = new FeatureDescriptor {
Extension = extensionDescriptor,
Name = entity.Key.ToString(),
};
Mapping featureMapping = (Mapping)entity.Value;
foreach (var featureEntity in featureMapping.Entities) {
if (String.Equals(featureEntity.Key.ToString(), "description", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Description = featureEntity.Value.ToString();
}
else if (String.Equals(featureEntity.Key.ToString(), "category", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Category = featureEntity.Value.ToString();
}
else if (String.Equals(featureEntity.Key.ToString(), "dependencies", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Dependencies = ParseFeatureDependenciesEntry(featureEntity.Value.ToString());
}
}
featureDescriptors.Add(featureDescriptor);
}
}
if (!featureDescriptors.Any(fd => fd.Name == extensionDescriptor.Name)) {
featureDescriptors.Add(new FeatureDescriptor {
Name = extensionDescriptor.Name,
Dependencies = new string[0],
Extension = extensionDescriptor,
});
}
return featureDescriptors;
}
private Feature LoadFeature(FeatureDescriptor featureDescriptor) { private Feature LoadFeature(FeatureDescriptor featureDescriptor) {
var featureName = featureDescriptor.Name; var featureName = featureDescriptor.Name;
string extensionName = GetExtensionForFeature(featureName); string extensionName = GetExtensionForFeature(featureName);
@@ -237,28 +172,5 @@ namespace Orchard.Environment.Extensions {
return null; return null;
} }
private static string[] ParseFeatureDependenciesEntry(string dependenciesEntry) {
List<string> dependencies = new List<string>();
foreach (var s in dependenciesEntry.Split(',')) {
dependencies.Add(s.Trim());
}
return dependencies.ToArray();
}
private static Mapping GetMapping(
IDictionary<string, DataItem> fields,
string key) {
DataItem value;
return fields.TryGetValue(key, out value) ? (Mapping)value : null;
}
private static string GetValue(
IDictionary<string, DataItem> fields,
string key) {
DataItem value;
return fields.TryGetValue(key, out value) ? value.ToString() : null;
}
} }
} }

View File

@@ -1,9 +1,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Caching;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Extensions.Folders { namespace Orchard.Environment.Extensions.Folders {
public class AreaFolders : ExtensionFolders { public class AreaFolders : ExtensionFolders {
public AreaFolders(IEnumerable<string> paths) : public AreaFolders(IEnumerable<string> paths, ICacheManager cacheManager, IVirtualPathProvider virtualPathProvider) :
base(paths, "Module.txt", true/*isManifestOptional*/) { base(paths, "Module.txt", true/*isManifestOptional*/, cacheManager, virtualPathProvider) {
} }
} }
} }

View File

@@ -1,19 +1,67 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Web.Hosting;
using Orchard.Caching;
using Orchard.Environment.Extensions.Helpers; using Orchard.Environment.Extensions.Helpers;
using Orchard.Environment.Extensions.Models;
using Orchard.Environment.FileSystems;
using Yaml.Grammar; using Yaml.Grammar;
namespace Orchard.Environment.Extensions.Folders { namespace Orchard.Environment.Extensions.Folders {
public class ParseResult {
public string Location { get; set; }
public string Name { get; set; }
public YamlDocument YamlDocument { get; set; }
}
public class ExtensionFolders : IExtensionFolders { public class ExtensionFolders : IExtensionFolders {
private readonly IEnumerable<string> _paths; private readonly IEnumerable<string> _paths;
private readonly string _manifestName; private readonly string _manifestName;
private readonly string _extensionType;
private readonly bool _manifestIsOptional; private readonly bool _manifestIsOptional;
private readonly ICacheManager _cacheManager;
private readonly IVirtualPathProvider _virtualPathProvider;
public ExtensionFolders(IEnumerable<string> paths, string manifestName, bool manifestIsOptional) { public ExtensionFolders(
IEnumerable<string> paths,
string manifestName,
bool manifestIsOptional,
ICacheManager cacheManager,
IVirtualPathProvider virtualPathProvider) {
_paths = paths; _paths = paths;
_manifestName = manifestName; _manifestName = manifestName;
_extensionType = manifestName == "Theme.txt" ? "Theme" : "Module";
_manifestIsOptional = manifestIsOptional; _manifestIsOptional = manifestIsOptional;
_cacheManager = cacheManager;
_virtualPathProvider = virtualPathProvider;
}
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
var virtualPaths = _cacheManager.Get("", ctx => {
var x = 5;
return new[] { "hello" };
});
var list = new List<ExtensionDescriptor>();
foreach (var virtualPath in virtualPaths) {
list.Add(GetExtensionDescriptor(virtualPath));
}
return list;
}
ExtensionDescriptor GetExtensionDescriptor(string virtualPath) {
return _cacheManager.Get(virtualPath, context => {
context.IsInvalid(_virtualPathProvider.WhenPathChanges(virtualPath));
var text = _virtualPathProvider.ReadAllText(virtualPath);
var parseResult = ParseManifest(text);
return GetDescriptorForExtension(parseResult.Name, parseResult);
});
} }
public IEnumerable<string> ListNames() { public IEnumerable<string> ListNames() {
@@ -43,10 +91,10 @@ namespace Orchard.Environment.Extensions.Folders {
if (File.Exists(extensionManifestPath)) { if (File.Exists(extensionManifestPath)) {
var yamlStream = YamlParser.Load(extensionManifestPath); var yamlStream = YamlParser.Load(extensionManifestPath);
return new ParseResult { return new ParseResult {
Location = path, Location = path,
Name = name, Name = name,
YamlDocument = yamlStream.Documents.Single() YamlDocument = yamlStream.Documents.Single()
}; };
} }
if (_manifestIsOptional) { if (_manifestIsOptional) {
@@ -55,13 +103,94 @@ namespace Orchard.Environment.Extensions.Folders {
bool success; bool success;
var yamlStream = parser.ParseYamlStream(yamlInput, out success); var yamlStream = parser.ParseYamlStream(yamlInput, out success);
return new ParseResult { return new ParseResult {
Location = path, Location = path,
Name = name, Name = name,
YamlDocument = yamlStream.Documents.Single() YamlDocument = yamlStream.Documents.Single()
}; };
} }
} }
return null; return null;
} }
private ExtensionDescriptor GetDescriptorForExtension(string name, ParseResult parseResult) {
var mapping = (Mapping)parseResult.YamlDocument.Root;
var fields = mapping.Entities
.Where(x => x.Key is Scalar)
.ToDictionary(x => ((Scalar)x.Key).Text, x => x.Value);
var extensionDescriptor = new ExtensionDescriptor {
Location = parseResult.Location,
Name = name,
ExtensionType = _extensionType,
DisplayName = GetValue(fields, "name") ?? name,
Description = GetValue(fields, "description"),
Version = GetValue(fields, "version"),
OrchardVersion = GetValue(fields, "orchardversion"),
Author = GetValue(fields, "author"),
WebSite = GetValue(fields, "website"),
Tags = GetValue(fields, "tags"),
AntiForgery = GetValue(fields, "antiforgery"),
};
extensionDescriptor.Features = GetFeaturesForExtension(GetMapping(fields, "features"), extensionDescriptor);
return extensionDescriptor;
}
private static IEnumerable<FeatureDescriptor> GetFeaturesForExtension(Mapping features, ExtensionDescriptor extensionDescriptor) {
List<FeatureDescriptor> featureDescriptors = new List<FeatureDescriptor>();
if (features != null) {
foreach (var entity in features.Entities) {
FeatureDescriptor featureDescriptor = new FeatureDescriptor {
Extension = extensionDescriptor,
Name = entity.Key.ToString(),
};
Mapping featureMapping = (Mapping)entity.Value;
foreach (var featureEntity in featureMapping.Entities) {
if (String.Equals(featureEntity.Key.ToString(), "description", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Description = featureEntity.Value.ToString();
}
else if (String.Equals(featureEntity.Key.ToString(), "category", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Category = featureEntity.Value.ToString();
}
else if (String.Equals(featureEntity.Key.ToString(), "dependencies", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Dependencies = ParseFeatureDependenciesEntry(featureEntity.Value.ToString());
}
}
featureDescriptors.Add(featureDescriptor);
}
}
if (!featureDescriptors.Any(fd => fd.Name == extensionDescriptor.Name)) {
featureDescriptors.Add(new FeatureDescriptor {
Name = extensionDescriptor.Name,
Dependencies = new string[0],
Extension = extensionDescriptor,
});
}
return featureDescriptors;
}
private static string[] ParseFeatureDependenciesEntry(string dependenciesEntry) {
List<string> dependencies = new List<string>();
foreach (var s in dependenciesEntry.Split(',')) {
dependencies.Add(s.Trim());
}
return dependencies.ToArray();
}
private static Mapping GetMapping(
IDictionary<string, DataItem> fields,
string key) {
DataItem value;
return fields.TryGetValue(key, out value) ? (Mapping)value : null;
}
private static string GetValue(
IDictionary<string, DataItem> fields,
string key) {
DataItem value;
return fields.TryGetValue(key, out value) ? value.ToString() : null;
}
} }
} }

View File

@@ -1,15 +1,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Environment.Extensions.Models;
using Yaml.Grammar; using Yaml.Grammar;
namespace Orchard.Environment.Extensions.Folders { namespace Orchard.Environment.Extensions.Folders {
public interface IExtensionFolders { public interface IExtensionFolders {
IEnumerable<string> ListNames(); IEnumerable<ExtensionDescriptor> AvailableExtensions();
ParseResult ParseManifest(string name);
} }
public class ParseResult {
public string Location { get; set; }
public string Name { get; set; }
public YamlDocument YamlDocument { get; set; }
}
} }

View File

@@ -1,9 +1,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Caching;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Extensions.Folders { namespace Orchard.Environment.Extensions.Folders {
public class ModuleFolders : ExtensionFolders { public class ModuleFolders : ExtensionFolders {
public ModuleFolders(IEnumerable<string> paths) : public ModuleFolders(IEnumerable<string> paths, ICacheManager cacheManager, IVirtualPathProvider virtualPathProvider) :
base(paths, "Module.txt", false/*isManifestOptional*/) { base(paths, "Module.txt", false/*isManifestOptional*/, cacheManager, virtualPathProvider) {
} }
} }
} }

View File

@@ -1,9 +1,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Caching;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Extensions.Folders { namespace Orchard.Environment.Extensions.Folders {
public class ThemeFolders : ExtensionFolders { public class ThemeFolders : ExtensionFolders {
public ThemeFolders(IEnumerable<string> paths) : public ThemeFolders(IEnumerable<string> paths, ICacheManager cacheManager, IVirtualPathProvider virtualPathProvider) :
base(paths, "Theme.txt", false/*manifestIsOptional*/) { base(paths, "Theme.txt", false/*manifestIsOptional*/, cacheManager, virtualPathProvider) {
} }
} }
} }

View File

@@ -3,33 +3,9 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Web.Hosting; using System.Web.Hosting;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Configuration { namespace Orchard.Environment.Configuration {
/// <summary>
/// Abstraction of App_Data folder
/// Expected to work on physical filesystem, but decouples core
/// system from web hosting apis
/// </summary>
public interface IAppDataFolder {
IEnumerable<string> ListFiles(string path);
IEnumerable<string> ListDirectories(string path);
void CreateFile(string path, string content);
string ReadFile(string path);
void DeleteFile(string path);
bool FileExists(string path);
string CreateDirectory(string path);
/// <summary>
/// May be called to initialize component when not in a hosting environment
/// app domain
/// </summary>
void SetBasePath(string basePath);
string MapPath(string path);
}
public class AppDataFolder : IAppDataFolder { public class AppDataFolder : IAppDataFolder {
protected string _basePath; protected string _basePath;

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Web.Hosting;
using Orchard.Caching.Providers;
using Orchard.Services;
namespace Orchard.Environment.FileSystems {
public class DefaultVirtualPathProvider : IVirtualPathProvider {
private readonly IClock _clock;
private readonly IList<IVolatileSink> _sinks = new List<IVolatileSink>();
//private string _cachePrefix = Guid.NewGuid().ToString("n");
public DefaultVirtualPathProvider(IClock clock) {
_clock = clock;
}
public string ReadAllText(string virtualPath) {
using (var stream = VirtualPathProvider.OpenFile(virtualPath)) {
using (var reader = new StreamReader(stream)) {
return reader.ReadToEnd();
}
}
//var cd = HostingEnvironment.VirtualPathProvider.. .GetCacheDependency(virtualPath, null, _clock.UtcNow);
//HostingEnvironment.Cache.Add(
// _cachePrefix + virtualPath,
// virtualPath,
// cd,
// NoAbsoluteExpiration,
// );
}
public IVolatileSignal WhenPathChanges(string virtualPath) {
return new VirtualPathSignal(this, virtualPath);
}
class VirtualPathSignal : IVolatileSignal {
private readonly string _virtualPath;
public VirtualPathSignal(DefaultVirtualPathProvider provider, string virtualPath) {
_virtualPath = virtualPath;
Provider = provider;
}
public IVolatileProvider Provider { get; set; }
}
public void Enlist(IVolatileSink sink) {
_sinks.Add(sink);
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
namespace Orchard.Environment.FileSystems {
/// <summary>
/// Abstraction of App_Data folder
/// Expected to work on physical filesystem, but decouples core
/// system from web hosting apis
/// </summary>
public interface IAppDataFolder {
IEnumerable<string> ListFiles(string path);
IEnumerable<string> ListDirectories(string path);
void CreateFile(string path, string content);
string ReadFile(string path);
void DeleteFile(string path);
bool FileExists(string path);
string CreateDirectory(string path);
/// <summary>
/// May be called to initialize component when not in a hosting environment
/// app domain
/// </summary>
void SetBasePath(string basePath);
string MapPath(string path);
}
}

View File

@@ -0,0 +1,9 @@
using Orchard.Caching.Providers;
namespace Orchard.Environment.FileSystems {
public interface IVirtualPathProvider : IVolatileProvider {
IVolatileSignal WhenPathChanges(string path);
string ReadAllText(string virtualPath);
}
}

View File

@@ -10,6 +10,7 @@ using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Folders; using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Loaders; using Orchard.Environment.Extensions.Loaders;
using Orchard.Environment.FileSystems;
using Orchard.Environment.ShellBuilders; using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Topology; using Orchard.Environment.Topology;
using Orchard.Events; using Orchard.Events;

View File

@@ -106,7 +106,8 @@ namespace Orchard.Environment.ShellBuilders {
private IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle> RegisterType(ContainerBuilder builder, ShellTopologyItem item) { private IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle> RegisterType(ContainerBuilder builder, ShellTopologyItem item) {
return builder.RegisterType(item.Type) return builder.RegisterType(item.Type)
.WithProperty("Feature", item.Feature); .WithProperty("Feature", item.Feature)
.WithMetadata("Feature", item.Feature);
} }
} }
} }

View File

@@ -2,7 +2,7 @@
using System.IO; using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Xml; using System.Xml;
using Orchard.Environment.Configuration; using Orchard.Environment.FileSystems;
using Orchard.Environment.Topology.Models; using Orchard.Environment.Topology.Models;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;

View File

@@ -1,17 +0,0 @@
using System;
using System.Web.Mvc;
namespace Orchard.Mvc.Extensions {
public static class ControllerExtensions {
public static RedirectResult ReturnUrlRedirect(this Controller controller) {
string returnUrl = controller.Request.QueryString["ReturnUrl"];
// prevents phishing attacks by using only relative urls
if(!returnUrl.StartsWith("/")) {
return new RedirectResult("~/");
}
return new RedirectResult(returnUrl);
}
}
}

View File

@@ -63,6 +63,18 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\sharpziplib\ICSharpCode.SharpZipLib.dll</HintPath> <HintPath>..\..\lib\sharpziplib\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference> </Reference>
<Reference Include="Machine.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c474de7a495cff1, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Core.dll</HintPath>
</Reference>
<Reference Include="Machine.Migrations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c474de7a495cff1, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.dll</HintPath>
</Reference>
<Reference Include="Machine.Migrations.NHibernate, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.NHibernate.dll</HintPath>
</Reference>
<Reference Include="NHibernate, Version=2.1.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL"> <Reference Include="NHibernate, Version=2.1.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\fluentnhibernate\NHibernate.dll</HintPath> <HintPath>..\..\lib\fluentnhibernate\NHibernate.dll</HintPath>
@@ -134,8 +146,14 @@
<Compile Include="Caching\AcquireContext.cs" /> <Compile Include="Caching\AcquireContext.cs" />
<Compile Include="Caching\Cache.cs" /> <Compile Include="Caching\Cache.cs" />
<Compile Include="Caching\DefaultCacheManager.cs" /> <Compile Include="Caching\DefaultCacheManager.cs" />
<Compile Include="Caching\Providers\IVolatileSink.cs" />
<Compile Include="Environment\FileSystems\DefaultVirtualPathProvider.cs" />
<Compile Include="Environment\FileSystems\IAppDataFolder.cs" />
<Compile Include="Environment\FileSystems\IVirtualPathProvider.cs" />
<Compile Include="Caching\ICache.cs" /> <Compile Include="Caching\ICache.cs" />
<Compile Include="Caching\ICacheManager.cs" /> <Compile Include="Caching\ICacheManager.cs" />
<Compile Include="Caching\Providers\IVolatileSignal.cs" />
<Compile Include="Caching\Providers\IVolatileProvider.cs" />
<Compile Include="Commands\CommandParameters.cs" /> <Compile Include="Commands\CommandParameters.cs" />
<Compile Include="Commands\CommandDescriptor.cs" /> <Compile Include="Commands\CommandDescriptor.cs" />
<Compile Include="Commands\CommandHandlerDescriptor.cs" /> <Compile Include="Commands\CommandHandlerDescriptor.cs" />
@@ -173,7 +191,7 @@
<Compile Include="Environment\AutofacUtil\DynamicProxy2\DynamicProxyContext.cs" /> <Compile Include="Environment\AutofacUtil\DynamicProxy2\DynamicProxyContext.cs" />
<Compile Include="Environment\AutofacUtil\DynamicProxy2\DynamicProxyExtensions.cs" /> <Compile Include="Environment\AutofacUtil\DynamicProxy2\DynamicProxyExtensions.cs" />
<Compile Include="Environment\AutofacUtil\DynamicProxy2\ConstructorFinderWrapper.cs" /> <Compile Include="Environment\AutofacUtil\DynamicProxy2\ConstructorFinderWrapper.cs" />
<Compile Include="Environment\Configuration\AppDataFolder.cs" /> <Compile Include="Environment\FileSystems\AppDataFolder.cs" />
<Compile Include="Environment\Configuration\ShellSettingsManager.cs" /> <Compile Include="Environment\Configuration\ShellSettingsManager.cs" />
<Compile Include="Environment\AutofacUtil\ContainerUpdater.cs" /> <Compile Include="Environment\AutofacUtil\ContainerUpdater.cs" />
<Compile Include="Environment\ShellBuilders\ShellContextFactory.cs" /> <Compile Include="Environment\ShellBuilders\ShellContextFactory.cs" />
@@ -204,7 +222,6 @@
<Compile Include="Modules\IModuleFeature.cs" /> <Compile Include="Modules\IModuleFeature.cs" />
<Compile Include="Modules\IModuleService.cs" /> <Compile Include="Modules\IModuleService.cs" />
<Compile Include="Mvc\AntiForgery\ValidateAntiForgeryTokenOrchardAttribute.cs" /> <Compile Include="Mvc\AntiForgery\ValidateAntiForgeryTokenOrchardAttribute.cs" />
<Compile Include="Mvc\Extensions\ControllerExtensions.cs" />
<Compile Include="Mvc\Extensions\ModelStateDictionaryExtensions.cs" /> <Compile Include="Mvc\Extensions\ModelStateDictionaryExtensions.cs" />
<Compile Include="Mvc\Html\FileRegistrationContextExtensions.cs" /> <Compile Include="Mvc\Html\FileRegistrationContextExtensions.cs" />
<Compile Include="Mvc\Extensions\UrlHelperExtensions.cs" /> <Compile Include="Mvc\Extensions\UrlHelperExtensions.cs" />