From f3dc7a33cd041cbbe5598d45c58a5445642a5cf8 Mon Sep 17 00:00:00 2001 From: eeichinger Date: Fri, 3 Oct 2008 09:53:16 +0000 Subject: [PATCH] refactored PageHandlerFactory and AbstractHandlerFactory --- .../Script/Services/ScriptHandlerFactory.cs | 26 ++- .../Web/Support/AbstractHandlerFactory.cs | 163 +++++++++++--- .../Web/Support/PageHandlerFactory.cs | 150 ++++++------- .../ReadOnlySession.aspx | 14 ++ .../Spring.Web.Tests.2005.csproj | 1 + .../Support/AbstractHandlerFactoryTests.cs | 199 +++++++++++++++--- .../Web/Support/PageHandlerFactoryTests.cs | 20 +- 7 files changed, 416 insertions(+), 157 deletions(-) create mode 100644 test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/ReadOnlySession.aspx diff --git a/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs b/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs index 86d0460e..eefc76d8 100644 --- a/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs +++ b/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs @@ -86,20 +86,11 @@ namespace Spring.Web.Script.Services public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) { string filename = VirtualPathUtility.ToAbsolute(context.Request.FilePath); - string cacheKey = (string)webServiceData_GetCacheKey.Invoke( - null, new object[] { VirtualPathUtility.ToAbsolute(context.Request.FilePath) }); + string cacheKey = (string)webServiceData_GetCacheKey.Invoke(null, new object[] { filename }); object webServiceData = context.Cache.Get(cacheKey); if (webServiceData == null) { - IConfigurableApplicationContext appContext = - WebApplicationContext.GetContext(url) as IConfigurableApplicationContext; - - if (appContext == null) - { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } - + IConfigurableApplicationContext appContext = base.GetCheckedApplicationContext(url); string appRelativeVirtualPath = WebUtils.GetAppRelativePath(url); NamedObjectDefinition nod = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); @@ -126,5 +117,18 @@ namespace Spring.Web.Script.Services { this.scriptHandlerFactory.ReleaseHandler(handler); } + + /// + /// Create a handler instance for the given URL. + /// + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// A handler instance for the current request. + protected override IHttpHandler CreateHandlerInstance( HttpContext context, string requestType, string url, string physicalPath ) + { + throw new NotSupportedException(); + } } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs index 71496b61..9ece991e 100644 --- a/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs @@ -20,9 +20,14 @@ #region Imports +using System; +using System.Collections; using System.IO; using System.Web; using Common.Logging; +using Spring.Collections; +using Spring.Context; +using Spring.Context.Support; using Spring.Objects.Factory.Config; using Spring.Util; @@ -43,17 +48,24 @@ namespace Spring.Web.Support /// Aleksandar Seovic public abstract class AbstractHandlerFactory : IHttpHandlerFactory { + /// + /// Holds all handlers having == true. + /// + private readonly IDictionary _reusableHandlerCache = new CaseInsensitiveHashtable(); + + /// + /// Holds the shared logger for all factories. + /// + protected readonly ILog Log; + /// /// Creates a new instance of the /// class. /// - /// - ///

- /// This is an abstract class and as such provides no public constructors. - ///

- ///
protected AbstractHandlerFactory() - {} + { + this.Log = LogManager.GetLogger( this.GetType() ); + } /// /// Returns an appropriate implementation. @@ -66,15 +78,59 @@ namespace Spring.Web.Support /// The HTTP method of the request. /// /// The request URL. - /// + /// /// The physical path of the requested resource. /// /// /// A new object that processes /// the request. /// - public abstract IHttpHandler GetHandler( - HttpContext context, string requestType, string url, string pathTranslated); + public virtual IHttpHandler GetHandler( HttpContext context, string requestType, string url, string physicalPath ) + { + bool isDebug = Log.IsDebugEnabled; + + #region Instrumentation + + if (isDebug) + Log.Debug( string.Format( "GetHandler():resolving url '{0}'", url ) ); + + #endregion + + IHttpHandler handler = null; + lock (_reusableHandlerCache.SyncRoot) + { + handler = (IHttpHandler)_reusableHandlerCache[url]; + } + + if (handler != null) + { + #region Instrumentation + + if (isDebug) + { + Log.Debug( string.Format( "GetHandler():resolved url '{0}' from reusable handler cache", url ) ); + } + + #endregion + + return handler; + } + + lock (_reusableHandlerCache.SyncRoot) + { + handler = (IHttpHandler)_reusableHandlerCache[url]; + if (handler == null) + { + handler = CreateHandlerInstance( context, requestType, url, physicalPath ); + + if (handler.IsReusable) + { + _reusableHandlerCache[url] = handler; + } + } + return handler; + } + } /// /// Enables a factory to release an existing @@ -83,8 +139,61 @@ namespace Spring.Web.Support /// /// The object to release. /// - public virtual void ReleaseHandler(IHttpHandler handler) - {} + public virtual void ReleaseHandler( IHttpHandler handler ) + { } + + /// + /// Create a handler instance for the given URL. + /// + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// A handler instance for processing the current request. + protected abstract IHttpHandler CreateHandlerInstance( HttpContext context, string requestType, string url, string physicalPath ); + + /// + /// Get the application context instance corresponding to the given absolute url and checks + /// it for contract and being not null. + /// + /// the absolute url + /// + /// if no context is found + /// + /// + /// if context is not an + /// + /// teh application context instance corresponding to the given absolute url. + /// + /// Calls to obtain a context instance. + /// + protected IConfigurableApplicationContext GetCheckedApplicationContext( string url ) + { + IApplicationContext appContext = GetContext( url ); + if (appContext == null) + { + throw new ArgumentException( string.Format( "no application context for virtual path '{0}'", url ) ); + } + if (!(appContext is IConfigurableApplicationContext)) + { + throw new InvalidOperationException( string.Format( "application context '{0}' for virtual path '{1}' must implement IConfigurableApplicationContext", appContext.ToString(), url ) ); + } + return (IConfigurableApplicationContext)appContext; + } + + /// + /// Returns the unchecked, raw application context for the given virtual path. + /// + /// the virtual path to get the context for. + /// the context or null. + /// + /// Subclasses may override this method to change the context source. + /// By default, is used for obtaining context instances. + /// + protected virtual IApplicationContext GetContext( string virtualPath ) + { + return WebApplicationContext.GetContext( virtualPath ); + } /// /// DO NOT USE - this is subject to change! @@ -98,27 +207,29 @@ namespace Spring.Web.Support /// /// Resolve an object definition by url. /// - protected internal static NamedObjectDefinition FindWebObjectDefinition(string appRelativeVirtualPath, IConfigurableListableObjectFactory objectFactory) + protected internal static NamedObjectDefinition FindWebObjectDefinition( string appRelativeVirtualPath, IConfigurableListableObjectFactory objectFactory ) { - ILog Log = LogManager.GetLogger(typeof(AbstractHandlerFactory)); + ILog Log = LogManager.GetLogger( typeof( AbstractHandlerFactory ) ); bool isDebug = Log.IsDebugEnabled; // lookup definition using app-relative url - if (isDebug) Log.Debug(string.Format("GetHandler():looking up definition for app-relative url '{0}'", appRelativeVirtualPath)); + if (isDebug) + Log.Debug( string.Format( "GetHandler():looking up definition for app-relative url '{0}'", appRelativeVirtualPath ) ); string objectDefinitionName = appRelativeVirtualPath; - IObjectDefinition pageDefinition = objectFactory.GetObjectDefinition(appRelativeVirtualPath, true); + IObjectDefinition pageDefinition = objectFactory.GetObjectDefinition( appRelativeVirtualPath, true ); if (pageDefinition == null) { // try using pagename+extension and pagename only - string pageExtension = Path.GetExtension(appRelativeVirtualPath); - string pageName = WebUtils.GetPageName(appRelativeVirtualPath); + string pageExtension = Path.GetExtension( appRelativeVirtualPath ); + string pageName = WebUtils.GetPageName( appRelativeVirtualPath ); // only looks in the specified object factory -- it will *not* search parent contexts - pageDefinition = objectFactory.GetObjectDefinition(pageName + pageExtension, false); + pageDefinition = objectFactory.GetObjectDefinition( pageName + pageExtension, false ); if (pageDefinition == null) { - pageDefinition = objectFactory.GetObjectDefinition(pageName, false); - if (pageDefinition != null) objectDefinitionName = pageName; + pageDefinition = objectFactory.GetObjectDefinition( pageName, false ); + if (pageDefinition != null) + objectDefinitionName = pageName; } else { @@ -128,20 +239,21 @@ namespace Spring.Web.Support if (pageDefinition != null) { if (isDebug) - Log.Debug(string.Format("GetHandler():found definition for page-name '{0}'", objectDefinitionName)); + Log.Debug( string.Format( "GetHandler():found definition for page-name '{0}'", objectDefinitionName ) ); } else { if (isDebug) - Log.Debug(string.Format("GetHandler():no definition found for page-name '{0}'", pageName)); + Log.Debug( string.Format( "GetHandler():no definition found for page-name '{0}'", pageName ) ); } } else { - if (isDebug) Log.Debug(string.Format("GetHandler():found definition for page-url '{0}'", appRelativeVirtualPath)); + if (isDebug) + Log.Debug( string.Format( "GetHandler():found definition for page-url '{0}'", appRelativeVirtualPath ) ); } - return (pageDefinition == null) ? (NamedObjectDefinition)null : new NamedObjectDefinition(objectDefinitionName, pageDefinition); + return (pageDefinition == null) ? (NamedObjectDefinition)null : new NamedObjectDefinition( objectDefinitionName, pageDefinition ); } /// @@ -155,7 +267,7 @@ namespace Spring.Web.Support /// /// DO NOT USE /// - public NamedObjectDefinition(string name, IObjectDefinition objectDefinition) + public NamedObjectDefinition( string name, IObjectDefinition objectDefinition ) { _name = name; _objectDefinition = objectDefinition; @@ -178,5 +290,4 @@ namespace Spring.Web.Support } } } - } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs index 59ad6166..705b6d67 100644 --- a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs @@ -68,10 +68,6 @@ namespace Spring.Web.Support /// Aleksandar Seovic public class PageHandlerFactory : AbstractHandlerFactory { - private readonly ILog Log = LogManager.GetLogger(typeof(PageHandlerFactory)); - - private readonly IDictionary pageHandlerWrappers = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); - /// /// Retrieves instance of the configured page from Spring web application context, /// or if page is not defined in Spring config file tries to find it using standard @@ -82,76 +78,59 @@ namespace Spring.Web.Support /// Requested page URL /// Translated server path for the page /// Instance of the IHttpHandler object that should be used to process request. - public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string physicalPath) + public override IHttpHandler GetHandler( HttpContext context, string requestType, string url, string physicalPath ) { - new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); + new SecurityPermission( SecurityPermissionFlag.UnmanagedCode ).Assert(); - bool isDebug = Log.IsDebugEnabled; - - if (isDebug) Log.Debug(string.Format("GetHandler():resolving url '{0}'", url)); + return base.GetHandler(context, requestType, url, physicalPath); + } + /// + /// Create a handler instance for the given URL. + /// + /// The instance for this request. + /// The HTTP data transfer method (GET, POST, ...) + /// The requested . + /// The physical path of the requested resource. + /// A handler instance for the current request. + protected override IHttpHandler CreateHandlerInstance( HttpContext context, string requestType, string url, string physicalPath ) + { IHttpHandler pageHandlerWrapper; + IConfigurableApplicationContext appContext = GetCheckedApplicationContext( url ); - lock (pageHandlerWrappers.SyncRoot) + if (appContext == null) { - pageHandlerWrapper = (PageHandlerWrapper)pageHandlerWrappers[url]; + throw new InvalidOperationException( + "Implementations of IApplicationContext must also implement IConfigurableApplicationContext" ); } - if (pageHandlerWrapper != null) + string appRelativeVirtualPath = WebUtils.GetAppRelativePath( url ); + NamedObjectDefinition namedPageDefinition = FindWebObjectDefinition( appRelativeVirtualPath, appContext.ObjectFactory ); + + if (namedPageDefinition != null) { - if (isDebug) + Type pageType = namedPageDefinition.ObjectDefinition.ObjectType; + if (typeof( IRequiresSessionState ).IsAssignableFrom( pageType )) { - Log.Debug(string.Format("GetHandler():resolved url '{0}' from reusable handler cache", url)); + pageHandlerWrapper = new SessionAwarePageHandlerWrapper( appContext, namedPageDefinition.Name, url, null ); + } + else + { + pageHandlerWrapper = new PageHandlerWrapper( appContext, namedPageDefinition.Name, url, null ); } } else { - IConfigurableApplicationContext appContext = - WebApplicationContext.GetContext(url) as IConfigurableApplicationContext; - - if (appContext == null) + Type pageType = WebObjectUtils.GetCompiledPageType( url ); + if (typeof( IRequiresSessionState ).IsAssignableFrom( pageType )) { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); - } - - string appRelativeVirtualPath = WebUtils.GetAppRelativePath(url); - NamedObjectDefinition namedPageDefinition = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); - - if (namedPageDefinition != null) - { - Type pageType = namedPageDefinition.ObjectDefinition.ObjectType; - if (typeof(IRequiresSessionState).IsAssignableFrom(pageType)) - { - pageHandlerWrapper = new SessionAwarePageHandlerWrapper(appContext, namedPageDefinition.Name, url, null); - } - else - { - pageHandlerWrapper = new PageHandlerWrapper(appContext, namedPageDefinition.Name, url, null); - } + pageHandlerWrapper = new SessionAwarePageHandlerWrapper( appContext, appRelativeVirtualPath, url, physicalPath ); } else { - Type pageType = WebObjectUtils.GetCompiledPageType(url); - if (typeof(IRequiresSessionState).IsAssignableFrom(pageType)) - { - pageHandlerWrapper = new SessionAwarePageHandlerWrapper(appContext, appRelativeVirtualPath, url, physicalPath); - } - else - { - pageHandlerWrapper = new PageHandlerWrapper(appContext, appRelativeVirtualPath, url, physicalPath); - } - } - - if (pageHandlerWrapper.IsReusable) - { - lock (pageHandlerWrappers.SyncRoot) - { - pageHandlerWrappers[url] = pageHandlerWrapper; - } + pageHandlerWrapper = new PageHandlerWrapper( appContext, appRelativeVirtualPath, url, physicalPath ); } } - return pageHandlerWrapper; } } @@ -169,15 +148,15 @@ namespace Spring.Web.Support { #if NET_2_0 && !MONO_2_0 private static readonly FieldInfo fiHttpContext_CurrentHandler = - typeof(HttpContext).GetField("_currentHandler", BindingFlags.NonPublic | BindingFlags.Instance); + typeof( HttpContext ).GetField( "_currentHandler", BindingFlags.NonPublic | BindingFlags.Instance ); #endif #if MONO_2_0 private static readonly FieldInfo fiHttpContext_CurrentHandler = typeof(HttpContext).GetField("handler", BindingFlags.NonPublic | BindingFlags.Instance); #endif #if NET_2_0 || !MONO_2_0 - private static readonly MethodInfo miPage_SetPreviousPage = - typeof(System.Web.UI.Page).GetMethod("SetPreviousPage", BindingFlags.NonPublic | BindingFlags.Instance); + private static readonly MethodInfo miPage_SetPreviousPage = + typeof( System.Web.UI.Page ).GetMethod( "SetPreviousPage", BindingFlags.NonPublic | BindingFlags.Instance ); #endif private readonly IApplicationContext appContext; @@ -202,7 +181,7 @@ namespace Spring.Web.Support /// Name of the page object to execute. /// Requested page URL. /// Translated server path for the page. - public PageHandlerWrapper(IApplicationContext appContext, string pageName, string url, string path) + public PageHandlerWrapper( IApplicationContext appContext, string pageName, string url, string path ) { this.appContext = appContext; this.pageId = pageName; @@ -215,8 +194,8 @@ namespace Spring.Web.Support /// /// Application context instance to retrieve page from. /// Name of the page object to execute. - public PageHandlerWrapper(IApplicationContext appContext, string pageName) - : this(appContext, pageName, null, null) + public PageHandlerWrapper( IApplicationContext appContext, string pageName ) + : this( appContext, pageName, null, null ) { } @@ -245,7 +224,7 @@ namespace Spring.Web.Support #endregion - void IHttpHandler.ProcessRequest(HttpContext context) + void IHttpHandler.ProcessRequest( HttpContext context ) { IHttpHandler handler = cachedHandler; @@ -257,11 +236,12 @@ namespace Spring.Web.Support } else { - handler = GetOrCreateProcessHandler(context); + handler = GetOrCreateProcessHandler( context ); } // note, that we don't care about sync here. The last call wins (it's the most current handler instance anyway) - if (handler.IsReusable) cachedHandler = handler; + if (handler.IsReusable) + cachedHandler = handler; } // replace handler proxy on context with "real" handler @@ -276,29 +256,29 @@ namespace Spring.Web.Support // fix this... if (this == context.CurrentHandler) { - fiHttpContext_CurrentHandler.SetValue(context, handler); + fiHttpContext_CurrentHandler.SetValue( context, handler ); } if (handler is System.Web.UI.Page) { - System.Web.UI.Page page = (Page) handler; + System.Web.UI.Page page = (Page)handler; -// TODO: to fix this would require a change to the Mono source as there is no mechanisim (public or private) for explicitly setting the -// PreviousPage at the moment + // TODO: to fix this would require a change to the Mono source as there is no mechanisim (public or private) for explicitly setting the + // PreviousPage at the moment #if !MONO_2_0 // During Server.Transfer/Execute() the PreviousPage property gets set if (this.PreviousPage != null) { - miPage_SetPreviousPage.Invoke(page, new object[] { this.PreviousPage }); + miPage_SetPreviousPage.Invoke( page, new object[] { this.PreviousPage } ); } #endif } #endif - ApplySharedState(handler); - ApplyDependencyInjection(handler); + ApplySharedState( handler ); + ApplyDependencyInjection( handler ); - handler.ProcessRequest(context); + handler.ProcessRequest( context ); } /// @@ -316,7 +296,7 @@ namespace Spring.Web.Support private IHttpHandler CreatePageInstance() { IHttpHandler handler; - handler = WebObjectUtils.CreatePageInstance(url); + handler = WebObjectUtils.CreatePageInstance( url ); if (handler is IApplicationContextAware) { ((IApplicationContextAware)handler).ApplicationContext = appContext; @@ -327,21 +307,21 @@ namespace Spring.Web.Support /// /// Gets or - if not found - creates a process handler instance. /// - private IHttpHandler GetOrCreateProcessHandler(HttpContext context) + private IHttpHandler GetOrCreateProcessHandler( HttpContext context ) { IHttpHandler handler = null; string processId = context.Request[AbstractProcessHandler.ProcessIdParamName]; if (processId != null) { - handler = (IHttpHandler)ProcessManager.GetProcess(processId); + handler = (IHttpHandler)ProcessManager.GetProcess( processId ); } if (handler == null) { - handler = (IHttpHandler)this.appContext.GetObject(this.pageId); + handler = (IHttpHandler)this.appContext.GetObject( this.pageId ); if (handler is IProcess) { - ((IProcess)handler).Start(url); + ((IProcess)handler).Start( url ); } } return handler; @@ -351,11 +331,11 @@ namespace Spring.Web.Support /// Apply dependency injection stuff on the handler. /// /// - private void ApplyDependencyInjection(IHttpHandler handler) + private void ApplyDependencyInjection( IHttpHandler handler ) { if (handler is Control) { - ControlInterceptor.EnsureControlIntercepted(appContext, (Control)handler); + ControlInterceptor.EnsureControlIntercepted( appContext, (Control)handler ); } else { @@ -369,11 +349,11 @@ namespace Spring.Web.Support /// /// Applies to the given handler if applicable. /// - private void ApplySharedState(IHttpHandler handler) + private void ApplySharedState( IHttpHandler handler ) { if (handler is ISharedStateAware) { - CheckIfPageWasRecompiled(handler); + CheckIfPageWasRecompiled( handler ); ((ISharedStateAware)handler).SharedState = this.handlerState; } } @@ -382,7 +362,7 @@ namespace Spring.Web.Support /// Checks, if page has been recompiled. Creates/discards handlerState if necessary. /// /// - private void CheckIfPageWasRecompiled(IHttpHandler handler) + private void CheckIfPageWasRecompiled( IHttpHandler handler ) { if (handlerType != handler.GetType()) { @@ -415,8 +395,8 @@ namespace Spring.Web.Support /// Name of the page object to execute. /// Requested page URL. /// Translated server path for the page. - public SessionAwarePageHandlerWrapper(IApplicationContext appContext, string pageName, string url, string path) - : base(appContext, pageName, url, path) + public SessionAwarePageHandlerWrapper( IApplicationContext appContext, string pageName, string url, string path ) + : base( appContext, pageName, url, path ) { } @@ -425,8 +405,8 @@ namespace Spring.Web.Support /// /// Application context instance to retrieve page from. /// Name of the page object to execute. - public SessionAwarePageHandlerWrapper(IApplicationContext appContext, string pageName) - : base(appContext, pageName) + public SessionAwarePageHandlerWrapper( IApplicationContext appContext, string pageName ) + : base( appContext, pageName ) { } } diff --git a/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/ReadOnlySession.aspx b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/ReadOnlySession.aspx new file mode 100644 index 00000000..6f84395b --- /dev/null +++ b/test/Spring/Spring.Web.Tests/Data/Spring/Web/Support/PageHandlerFactoryTests/ReadOnlySession.aspx @@ -0,0 +1,14 @@ +<%@ Page language="c#" EnableSessionState="ReadOnly" AutoEventWireup="false" Inherits="Spring.Web.UI.Page" %><%=Session.IsReadOnly?"OK":"NOK"%> \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2005.csproj b/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2005.csproj index 4273cc33..cc126dab 100644 --- a/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2005.csproj +++ b/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2005.csproj @@ -131,6 +131,7 @@ + diff --git a/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs index 00083135..5bc8c1ac 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs @@ -23,6 +23,8 @@ using System; using System.Web; using NUnit.Framework; +using Rhino.Mocks; +using Spring.Context; using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; @@ -35,51 +37,180 @@ namespace Spring.Web.Support /// /// Erich Eichinger [TestFixture] - public class AbstractHandlerFactoryTests : AbstractHandlerFactory + public class AbstractHandlerFactoryTests { - private class Type1 {} - + #region TestFindWebObjectDefinition Helper + + private class TestFindWebObjectDefinitionHandlerFactory : AbstractHandlerFactory + { + private class Type1 { } + + public void TestFindWebObjectDefinition() + { + NamedObjectDefinition nod; + + nod = Find( "/path/o1.ext", "/path/o1.ext" ); + Assert.AreEqual( typeof( Type1 ), nod.ObjectDefinition.ObjectType ); + Assert.AreEqual( "/path/o1.ext", nod.Name ); + + nod = Find( "/path/o1.ext", "/o1.ext" ); + Assert.IsNull( nod ); + + nod = Find( "/path/o1.ext", "/path/o1" ); + Assert.IsNull( nod ); + + nod = Find( "/path/o1.ext", "o1.ext" ); + Assert.AreEqual( typeof( Type1 ), nod.ObjectDefinition.ObjectType ); + Assert.AreEqual( "o1.ext", nod.Name ); + + nod = Find( "/path/o1.ext", "o1" ); + Assert.AreEqual( typeof( Type1 ), nod.ObjectDefinition.ObjectType ); + Assert.AreEqual( "o1", nod.Name ); + } + + private static NamedObjectDefinition Find( string url, string objectName ) + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + RootObjectDefinition rod = new RootObjectDefinition( typeof( Type1 ) ); + of.RegisterObjectDefinition( objectName, rod ); + + return FindWebObjectDefinition( url, of ); + } + + #region AbstractHandlerFactory implementations + + protected override IHttpHandler CreateHandlerInstance( HttpContext context, string requestType, string url, string physicalPath ) + { + throw new NotImplementedException(); + } + + #endregion + } + + #endregion TestFindWebObjectDefinition Helper + [Test] public void FindWebObjectDefinition() { - NamedObjectDefinition nod; - - nod = Find("/path/o1.ext", "/path/o1.ext"); - Assert.AreEqual( typeof(Type1), nod.ObjectDefinition.ObjectType); - Assert.AreEqual( "/path/o1.ext", nod.Name); - - nod = Find("/path/o1.ext", "/o1.ext"); - Assert.IsNull(nod); - - nod = Find("/path/o1.ext", "/path/o1"); - Assert.IsNull(nod); - - nod = Find("/path/o1.ext", "o1.ext"); - Assert.AreEqual(typeof(Type1), nod.ObjectDefinition.ObjectType); - Assert.AreEqual("o1.ext", nod.Name); - - nod = Find("/path/o1.ext", "o1"); - Assert.AreEqual(typeof(Type1), nod.ObjectDefinition.ObjectType); - Assert.AreEqual("o1", nod.Name); + TestFindWebObjectDefinitionHandlerFactory f = new TestFindWebObjectDefinitionHandlerFactory(); + f.TestFindWebObjectDefinition(); } - private NamedObjectDefinition Find(string url, string objectName) + #region TestHandlerFactory + + public class TestHandlerFactory : AbstractHandlerFactory { - DefaultListableObjectFactory of = new DefaultListableObjectFactory(); - RootObjectDefinition rod = new RootObjectDefinition(typeof(Type1)); - of.RegisterObjectDefinition(objectName, rod); + public new IConfigurableApplicationContext GetCheckedApplicationContext(string virtualPath) + { + return base.GetCheckedApplicationContext(virtualPath); + } - return FindWebObjectDefinition( url, of ); + protected override IHttpHandler CreateHandlerInstance(HttpContext context, string requestType, string url, string physicalPath ) + { + return CreateHandlerInstanceStub(context, requestType, url, physicalPath); + } + + public virtual IHttpHandler CreateHandlerInstanceStub(HttpContext context, string requestType, string url, string physicalPath) + { + throw new NotImplementedException(); + } + + protected override IApplicationContext GetContext( string virtualPath ) + { + return GetContextStub( virtualPath ); + } + + public virtual IApplicationContext GetContextStub( string virtualPath ) + { + throw new NotImplementedException(); + } } - #region AbstractHandlerFactory implementations - - public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, - string pathTranslated) - { - throw new NotImplementedException(); - } #endregion + + [Test] + public void GetCheckedApplicationContextThrowsExceptionsOnNonConfigurableContexts() + { + MockRepository mocks = new MockRepository(); + TestHandlerFactory f = (TestHandlerFactory) mocks.PartialMock(typeof(TestHandlerFactory)); + IApplicationContext simpleAppContext = (IApplicationContext) mocks.Stub(typeof(IApplicationContext)); + IConfigurableApplicationContext allowedAppContext = (IConfigurableApplicationContext) mocks.Stub(typeof(IConfigurableApplicationContext)); + + using(mocks.Record()) + { + Expect.Call(f.GetContextStub("/NullContext")).Return(null); + Expect.Call(f.GetContextStub("/NonConfigurableContext")).Return(simpleAppContext); + Expect.Call(f.GetContextStub("/AllowedContext")).Return(allowedAppContext); + } + + // (context == null) -> ArgumentException + try + { + f.GetCheckedApplicationContext("/NullContext"); + Assert.Fail("should throw ArgumentException"); + } + catch (ArgumentException) + {} + + // !(context is IConfigurableApplicationContext) -> InvalidOperationException + try + { + f.GetCheckedApplicationContext("/NonConfigurableContext"); + Assert.Fail("should throw InvalidOperationException"); + } + catch (InvalidOperationException) + {} + + // (context is IConfigurableApplicationContext) -> OK + Assert.AreSame(allowedAppContext, f.GetCheckedApplicationContext("/AllowedContext")); + } + + [Test] + public void CachesReusableHandlers() + { + MockRepository mocks = new MockRepository(); + TestHandlerFactory f = (TestHandlerFactory) mocks.PartialMock(typeof(TestHandlerFactory)); + IHttpHandler reusableHandler = (IHttpHandler) mocks.Stub(typeof(IHttpHandler)); + Expect.Call(reusableHandler.IsReusable).Return(true); + IHttpHandler reusableHandler2 = (IHttpHandler) mocks.Stub(typeof(IHttpHandler)); + Expect.Call(reusableHandler2.IsReusable).Return(true); + + // if (IHttpHandler.IsReusable == true) => always returns the same handler instance + // - CreateHandlerInstance() is only called once + using(mocks.Record()) + { + Expect.Call(f.CreateHandlerInstanceStub(null, null, "reusable", null)).Return(reusableHandler); + } + using (mocks.Playback()) + { + Assert.AreSame( reusableHandler, f.GetHandler( null, null, "reusable", null ) ); + Assert.AreSame( reusableHandler, f.GetHandler( null, null, "reusable", null ) ); + } + } + + [Test] + public void DoesntCacheNonReusableHandlers() + { + MockRepository mocks = new MockRepository(); + TestHandlerFactory f = (TestHandlerFactory) mocks.PartialMock(typeof(TestHandlerFactory)); + IHttpHandler nonReusableHandler = (IHttpHandler) mocks.DynamicMock(typeof(IHttpHandler)); + Expect.Call(nonReusableHandler.IsReusable).Return(false); + IHttpHandler nonReusableHandler2 = (IHttpHandler) mocks.DynamicMock(typeof(IHttpHandler)); + Expect.Call(nonReusableHandler2.IsReusable).Return(false); + + // if (IHttpHandler.IsReusable == false) => always create new handler instance + // - CreateHandlerInstance() is called for each request + using(mocks.Record()) + { + Expect.Call(f.CreateHandlerInstanceStub(null, null, "notreusable", null)).Return(nonReusableHandler); + Expect.Call(f.CreateHandlerInstanceStub(null, null, "notreusable", null)).Return(nonReusableHandler2); + } + using (mocks.Playback()) + { + Assert.AreSame( nonReusableHandler, f.GetHandler( null, null, "notreusable", null ) ); + Assert.AreSame( nonReusableHandler2, f.GetHandler( null, null, "notreusable", null ) ); + } + } } } \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/Web/Support/PageHandlerFactoryTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/PageHandlerFactoryTests.cs index 714902bc..560537ca 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/PageHandlerFactoryTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/PageHandlerFactoryTests.cs @@ -48,6 +48,14 @@ namespace Spring.Web.Support Assert.AreEqual("OK", result); } + [Test, Explicit] + public void UsesReadonlySession() + { + AspTestClient client = new AspTestClient(); + string result = client.GetPage("ReadOnlySession.aspx"); + Assert.AreEqual("OK", result); + } + [Test] public void MaintainsSession() { @@ -60,7 +68,7 @@ namespace Spring.Web.Support result = client.GetPage("MaintainsSession2.aspx"); Assert.AreEqual("OK", result); } - + [Test] public void BCLPageHandlerFactoryBehavior() { @@ -125,4 +133,14 @@ namespace Spring.Web.Support } #endif } + + [TestFixture] + public class PageHandlerFactoryStandaloneTests + { + [Test] + public void PageUsesReadonlySessionState() + { + + } + } } \ No newline at end of file