#region License
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Collections;
using Spring.Collections;
using Spring.Util;
using Spring.Web.UI;
#endregion
namespace Spring.Web.Support{
/// <summary>
/// A result factory is responsible for create an <see cref="IResult"/> instance from a given string representation.
/// </summary>
/// <remarks>
/// <para>
/// Factories get registered with the <see cref="ResultFactoryRegistry"/> for a certain <i>resultMode</i> string.
/// <see cref="DefaultResultWebNavigator"/> uses <see cref="ResultFactoryRegistry"/> for converting strings into <see cref="IResult"/> instances
/// implementing the corresponding navigation logic.
/// </para>
/// <para>
/// Result string representations are always of the form:<br/>
/// <c>"<resultmode>:<textual result representation>"</c><br/>
/// Calling <see cref="CreateResult"/> on the registry will cause the registry to first extract the leading <c>resultmode</c> to obtain
/// the corresponding <see cref="IResultFactory"/> instance and handle the actual <see cref="IResult"/> instantiation by delegating to
/// <see cref="IResultFactory.CreateResult"/>.
/// </para>
/// <example>
/// The following example illustrates the usual flow:
/// <code>
/// class MySpecialResultLogic : IResult
/// {
/// ...
/// }
///
/// class MySpecialResultLogicFactory : IResultFactory
/// {
/// IResult Create( string mode, string expression ) { /* ... convert 'expression' into
/// MySpecialResultLogic */ }
/// }
///
/// // register with global factory
/// ResultFactoryRegistry.RegisterResultFactory( "mySpecialMode", new MySpecialResultLogicFactory );
///
/// // configure your Results
/// <object type="mypage.aspx">
/// <property name="Results">
/// <dictionary>
/// <entry key="continue" value="mySpecialMode:<some MySpecialResultLogic string representation>" />
/// </dictionary>
/// </property>
///
/// // on your page call
/// myPage.SetResult("continue");
/// </code>
/// </example>
/// </remarks>
/// <seealso cref="ResultFactoryRegistry"/>
/// <seealso cref="IResult"/>
/// <seealso cref="Result"/>
/// <seealso cref="DefaultResultWebNavigator"/>
/// <seealso cref="Page.SetResult(string, object)"/>
/// <seealso cref="UserControl.SetResult(string, object)"/>
/// <author>Erich Eichinger</author>
public class ResultFactoryRegistry
{
private static readonly IDictionary s_registeredFactories = new CaseInsensitiveHashtable();
private static volatile IResultFactory s_defaultFactory;
static ResultFactoryRegistry()
{
Reset();
}
/// <summary>
/// Resets the factory registry to its defaults. Mainly used for unit testing.
/// </summary>
public static void Reset()
{
s_defaultFactory = null;
s_registeredFactories.Clear();
SetDefaultFactory( new DefaultResultFactory() );
foreach(string resultMode in Enum.GetNames(typeof(ResultMode)))
{
RegisterResultMode( resultMode, DefaultResultFactory );
}
}
/// <summary>
/// Returns the current <see cref="IResultFactory"/> set by <see cref="SetDefaultFactory"/>. Will never be null.
/// </summary>
/// <remarks>
/// The default factory is responsible for handling any unknown result modes.
/// </remarks>
public static IResultFactory DefaultResultFactory
{
get { return s_defaultFactory; }
}
/// <summary>
/// Set a new default factory
/// </summary>
/// <param name="resultFactory">the new default factory instance. Must not be null.</param>
/// <returns>the previous default factory.</returns>
public static IResultFactory SetDefaultFactory(IResultFactory resultFactory)
{
AssertUtils.ArgumentNotNull(resultFactory, "resultFactory");
IResultFactory prevFactory = s_defaultFactory;
s_defaultFactory = resultFactory;
return prevFactory;
}
/// <summary>
/// Registers a <see cref="IResultFactory"/> for the specified <paramref name="resultMode"/>.
/// </summary>
/// <param name="resultMode">the resultMode. Must not be null.</param>
/// <param name="resultFactory">the factory respponsible for handling <paramref name="resultMode"/> results. Must not be null.</param>
/// <returns>the factory previously registered for the specified <paramref name="resultMode"/>, if any.</returns>
/// <remarks>
/// See <see cref="ResultFactoryRegistry"/> overview for more information.
/// </remarks>
public static IResultFactory RegisterResultMode( string resultMode, IResultFactory resultFactory )
{
AssertUtils.ArgumentHasText(resultMode, "resultMode");
AssertUtils.ArgumentNotNull(resultFactory, "resultFactory");
lock (s_registeredFactories.SyncRoot)
{
IResultFactory prevFactory = (IResultFactory) s_registeredFactories[resultMode];
s_registeredFactories[resultMode] = resultFactory;
return prevFactory;
}
}
/// <summary>
/// Creates a result from the specified <paramref name="resultText"/> by extracting the result mode from
/// the text and delegating to a corresponding <see cref="IResultFactory"/>, if any.
/// </summary>
/// <param name="resultText">the 'resultmode'-prefixed textual representation of the result instance to create.</param>
/// <returns>
/// the <see cref="IResult"/> instance corresponding to the textual <paramref name="resultText"/> represenation,
/// created by the <see cref="IResultFactory"/>
/// </returns>
/// <exception cref="ArgumentNullException">
/// if either <paramref name="resultText"/> is null or <see cref="IResultFactory.CreateResult"/> returned null.</exception>
/// <remarks>
/// This method guarantees that the return value will always be non-null.<br/>
/// <paramref name="resultText"/> must always be of the form <c>"<resultmode>:<textual result representation>"</c>.
/// The <c>resultmode</c> will be extracted and the corresponding <see cref="IResultFactory"/> (previously registered
/// using <see cref="RegisterResultMode"/>) is called to actually create the <see cref="IResult"/> instance. If no factory matches
/// <c>resultmode</c>, the call is handled to the <see cref="DefaultResultFactory"/>.
/// </remarks>
public static IResult CreateResult( string resultText )
{
AssertUtils.ArgumentNotNull(resultText, "resultText");
IResultFactory resultFactory = null;
string resultMode = null;
int indexOfResultModeDelimiter = resultText.IndexOf( ':' );
if (indexOfResultModeDelimiter > 0)
{
resultMode = resultText.Substring( 0, indexOfResultModeDelimiter ).Trim();
resultFactory = (IResultFactory) s_registeredFactories[resultMode];
resultText = resultText.Substring( indexOfResultModeDelimiter + 1 );
}
if (resultFactory == null)
{
resultFactory = s_defaultFactory;
}
IResult result = resultFactory.CreateResult( resultMode, resultText );
AssertUtils.ArgumentNotNull(result, "ResultFactories must not return null results");
return result;
}
}
}
|