fixed SPRNET-1204: added Server Component support

This commit is contained in:
eeichinger
2009-05-13 16:16:05 +00:00
parent ab9683d9c9
commit e4ecb38507
17 changed files with 1109 additions and 430 deletions

View File

@@ -1,5 +1,5 @@
#region License
#region License
/*
* Copyright <20> 2002-2005 the original author or authors.
*
@@ -14,333 +14,449 @@
* 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.Specialized;
using System.Configuration;
using System.IO;
using System.Xml;
using Common.Logging;
using Spring.Core;
using Spring.Core.IO;
using Spring.Core.TypeResolution;
using Spring.Util;
#endregion
namespace Spring.Objects.Factory.Config
{
/// <summary>
/// Various utility methods for .NET style .config files.
/// </summary>
/// <remarks>
/// <p>
/// Currently supports reading custom configuration sections and returning them as
/// <see cref="System.Collections.Specialized.NameValueCollection"/> objects.
/// </p>
/// </remarks>
/// <author>Simon White</author>
/// <author>Mark Pollack</author>
public sealed class ConfigurationReader
{
private const string ConfigSectionTypeAttribute = "type";
private const string ConfigurationElement = "configuration";
private const string ConfigSectionsElement = "configSections";
private const string ConfigSectionElement = "section";
private const string ConfigSectionNameAttribute = "name";
private static readonly ILog _log = LogManager.GetLogger(typeof (ConfigurationReader));
/// <summary>
/// Reads the specified configuration section into a
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
/// <param name="resource">The resource to read.</param>
/// <param name="configSection">The section name.</param>
/// <returns>
/// A newly populated
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </returns>
/// <exception cref="System.IO.IOException">
/// If any errors are encountered while attempting to open a stream
/// from the supplied <paramref name="resource"/>.
/// </exception>
/// <exception cref="System.Xml.XmlException">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.1 and greater of the .NET Framework) the actual XML.
/// </exception>
/// <exception cref="System.Exception">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.0 of the .NET Framework).
/// </exception>
/// <exception cref="Spring.Objects.FatalObjectException">
/// If the configuration section was otherwise invalid.
/// </exception>
public static NameValueCollection Read(IResource resource, string configSection)
{
return ConfigurationReader.Read(resource, configSection, new NameValueCollection());
}
/// <summary>
/// Reads the specified configuration section into the supplied
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
/// <param name="resource">The resource to read.</param>
/// <param name="configSection">The section name.</param>
/// <param name="properties">
/// The collection that is to be populated. May be
/// <see langword="null"/>.
/// </param>
/// <returns>
/// A newly populated
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </returns>
/// <exception cref="System.IO.IOException">
/// If any errors are encountered while attempting to open a stream
/// from the supplied <paramref name="resource"/>.
/// </exception>
/// <exception cref="System.Xml.XmlException">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.1 and greater of the .NET Framework) the actual XML.
/// </exception>
/// <exception cref="System.Exception">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.0 of the .NET Framework).
/// </exception>
/// <exception cref="Spring.Objects.FatalObjectException">
/// If the configuration section was otherwise invalid.
/// </exception>
public static NameValueCollection Read(
IResource resource, string configSection, NameValueCollection properties)
{
return ConfigurationReader.Read(resource, configSection, properties, true);
}
/// <summary>
/// Reads the specified configuration section into the supplied
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
/// <param name="resource">The resource to read.</param>
/// <param name="configSection">The section name.</param>
/// <param name="properties">
/// The collection that is to be populated. May be
/// <see langword="null"/>.
/// </param>
/// <param name="overrideValues">
/// If a key already exists, is its value to be appended to the current
/// value or replaced?
/// </param>
/// <returns>
/// The populated
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </returns>
/// <exception cref="System.IO.IOException">
/// If any errors are encountered while attempting to open a stream
/// from the supplied <paramref name="resource"/>.
/// </exception>
/// <exception cref="System.Xml.XmlException">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.1 and greater of the .NET Framework) the actual XML.
/// </exception>
/// <exception cref="System.Exception">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.0 of the .NET Framework).
/// </exception>
/// <exception cref="Spring.Objects.FatalObjectException">
/// If the configuration section was otherwise invalid.
/// </exception>
public static NameValueCollection Read(
IResource resource, string configSection, NameValueCollection properties, bool overrideValues)
{
if (properties == null)
{
properties = new NameValueCollection();
}
Stream stream = null;
try
{
XmlDocument doc = new XmlDocument();
stream = resource.InputStream;
doc.Load(stream);
NameValueCollection newProperties = ReadFromXmlDocument(doc, configSection);
if(newProperties != null)
{
PopulateProperties(overrideValues, properties, newProperties);
}
}
finally
{
if (stream != null)
{
try
{
stream.Close();
}
catch (IOException ex)
{
#region Instrumentation
if (_log.IsWarnEnabled)
{
_log.Warn("Could not close stream from resource " + resource.Description, ex);
}
#endregion
}
}
}
return properties;
}
/// <summary>
/// Read from the specified configuration from the supplied XML
/// <paramref name="document"/> into a
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
/// <remarks>
/// <note>
/// Does <b>not</b> support section grouping. The supplied XML
/// <paramref name="document"/> must already be loaded.
/// </note>
/// </remarks>
/// <param name="document">
/// The <see cref="System.Xml.XmlDocument"/> to read from.
/// </param>
/// <param name="configSectionName">
/// The configuration section name to read.
/// </param>
/// <returns>
/// A newly populated
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </returns>
/// <exception cref="System.Xml.XmlException">
/// If any errors are encountered while reading (this only applies to
/// v1.1 and greater of the .NET Framework).
/// </exception>
/// <exception cref="System.Exception">
/// If any errors are encountered while reading (this only applies to
/// v1.0 of the .NET Framework).
/// </exception>
/// <exception cref="Spring.Objects.FatalObjectException">
/// If the configuration section was otherwise invalid.
/// </exception>
public static NameValueCollection ReadFromXmlDocument(XmlDocument document,
string configSectionName)
{
// find the config section declaration (if one exists)...
XmlNode xmlConfig = document.SelectSingleNode(
string.Format("//{0}//{1}//{2}[@{3}='{4}']",
ConfigurationElement, ConfigSectionsElement,
ConfigSectionElement, ConfigSectionNameAttribute, configSectionName));
// create appropriate configuration section handler...
NameValueSectionHandler handler = null;
if (xmlConfig == null)
{
// none specified, so use the default...
handler = new NameValueSectionHandler();
}
else
{
XmlAttribute xmlConfigType = xmlConfig.Attributes[ConfigSectionTypeAttribute];
Type cshType = TypeResolutionUtils.ResolveType(xmlConfigType.Value);
object o = ObjectUtils.InstantiateType(cshType);
handler = o as NameValueSectionHandler;
if (handler == null)
{
throw ConfigurationUtils.CreateConfigurationException("Configuration section '" + configSectionName + "' not of type NameValueCollection.");
}
}
XmlNode collectionNode = document.SelectSingleNode(
string.Format("//{0}//{1}", ConfigurationElement, configSectionName));
if (collectionNode == null)
{
throw ConfigurationUtils.CreateConfigurationException("Cannot read properties; config section '" + configSectionName + "' not found.");
}
else
{
return (NameValueCollection) handler.Create(null, null, collectionNode);
}
}
/// <summary>
/// Populates the supplied <paramref name="properties"/> with values from
/// a .NET application configuration file.
/// </summary>
/// <param name="properties">
/// The <see cref="System.Collections.Specialized.NameValueCollection"/>
/// to add any key-value pairs to.
/// </param>
/// <param name="configSectionName">
/// The configuration section name in the a .NET application configuration
/// file.
/// </param>
/// <param name="overrideValues">
/// If a key already exists, is its value to be appended to the current
/// value or replaced?
/// </param>
/// <returns>
/// <see langword="true"/> if the supplied
/// <paramref name="configSectionName"/> was found.
/// </returns>
public static bool PopulateFromAppConfig(
NameValueCollection properties, string configSectionName, bool overrideValues)
{
bool sectionFound = false;
NameValueCollection newProperties
= ConfigurationUtils.GetSection(configSectionName) as NameValueCollection;
if (newProperties != null)
{
sectionFound = true;
PopulateProperties(overrideValues, properties, newProperties);
}
return sectionFound;
}
private static void PopulateProperties(
bool overrideValues, NameValueCollection properties, NameValueCollection newProperties)
{
if (!overrideValues)
{
properties.Add(newProperties);
}
else
{
foreach (string key in newProperties.AllKeys)
{
properties.Set(key, newProperties.Get(key));
}
}
}
#region Constructor (s) / Destructor
// CLOVER:OFF
/// <summary>
/// Creates a new instance of the ConfigurationReader class.
/// </summary>
/// <remarks>
/// <p>
/// This is a utility class, and as such has no publicly visible
/// constructors.
/// </p>
/// </remarks>
private ConfigurationReader()
{
}
// CLOVER:ON
#endregion
}
*/
#endregion
#region Imports
using System;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Xml;
using Common.Logging;
using Spring.Core;
using Spring.Core.IO;
using Spring.Core.TypeResolution;
using Spring.Util;
using ConfigurationException=Common.Logging.ConfigurationException;
using ConfigXmlDocument = Spring.Util.ConfigXmlDocument;
#endregion
namespace Spring.Objects.Factory.Config
{
/// <summary>
/// Various utility methods for .NET style .config files.
/// </summary>
/// <remarks>
/// <p>
/// Currently supports reading custom configuration sections and returning them as
/// <see cref="System.Collections.Specialized.NameValueCollection"/> objects.
/// </p>
/// </remarks>
/// <author>Simon White</author>
/// <author>Mark Pollack</author>
public sealed class ConfigurationReader
{
private const string ConfigSectionTypeAttribute = "type";
private const string ConfigurationElement = "configuration";
private const string ConfigSectionsElement = "configSections";
private const string ConfigSectionGroupElement = "sectionGroup";
private const string ConfigSectionElement = "section";
private const string ConfigSectionNameAttribute = "name";
private static readonly ILog _log = LogManager.GetLogger(typeof(ConfigurationReader));
/// <summary>
/// Initializes the type members
/// </summary>
static ConfigurationReader()
{}
/// <summary>
/// Reads the specified configuration section into a
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
/// <param name="resource">The resource to read.</param>
/// <param name="configSection">The section name.</param>
/// <returns>
/// A newly populated
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </returns>
/// <exception cref="System.IO.IOException">
/// If any errors are encountered while attempting to open a stream
/// from the supplied <paramref name="resource"/>.
/// </exception>
/// <exception cref="System.Xml.XmlException">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.1 and greater of the .NET Framework) the actual XML.
/// </exception>
/// <exception cref="System.Exception">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.0 of the .NET Framework).
/// </exception>
/// <exception cref="Spring.Objects.FatalObjectException">
/// If the configuration section was otherwise invalid.
/// </exception>
public static NameValueCollection Read(IResource resource, string configSection)
{
return ConfigurationReader.Read(resource, configSection, new NameValueCollection());
}
/// <summary>
/// Reads the specified configuration section into the supplied
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
/// <param name="resource">The resource to read.</param>
/// <param name="configSection">The section name.</param>
/// <param name="properties">
/// The collection that is to be populated. May be
/// <see langword="null"/>.
/// </param>
/// <returns>
/// A newly populated
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </returns>
/// <exception cref="System.IO.IOException">
/// If any errors are encountered while attempting to open a stream
/// from the supplied <paramref name="resource"/>.
/// </exception>
/// <exception cref="System.Xml.XmlException">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.1 and greater of the .NET Framework) the actual XML.
/// </exception>
/// <exception cref="System.Exception">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.0 of the .NET Framework).
/// </exception>
/// <exception cref="Spring.Objects.FatalObjectException">
/// If the configuration section was otherwise invalid.
/// </exception>
public static NameValueCollection Read(
IResource resource, string configSection, NameValueCollection properties)
{
return ConfigurationReader.Read(resource, configSection, properties, true);
}
/// <summary>
/// Reads the specified configuration section into the supplied
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
/// <param name="resource">The resource to read.</param>
/// <param name="configSection">The section name.</param>
/// <param name="properties">
/// The collection that is to be populated. May be
/// <see langword="null"/>.
/// </param>
/// <param name="overrideValues">
/// If a key already exists, is its value to be appended to the current
/// value or replaced?
/// </param>
/// <returns>
/// The populated
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </returns>
/// <exception cref="System.IO.IOException">
/// If any errors are encountered while attempting to open a stream
/// from the supplied <paramref name="resource"/>.
/// </exception>
/// <exception cref="System.Xml.XmlException">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.1 and greater of the .NET Framework) the actual XML.
/// </exception>
/// <exception cref="System.Exception">
/// If any errors are encountered while loading or reading (this only applies to
/// v1.0 of the .NET Framework).
/// </exception>
/// <exception cref="Spring.Objects.FatalObjectException">
/// If the configuration section was otherwise invalid.
/// </exception>
public static NameValueCollection Read(
IResource resource, string configSection, NameValueCollection properties, bool overrideValues)
{
if (properties == null)
{
properties = new NameValueCollection();
}
Stream stream = null;
try
{
ConfigXmlDocument doc = new ConfigXmlDocument();
stream = resource.InputStream;
doc.Load(stream);
NameValueCollection newProperties = ReadFromXmlDocument(doc, configSection);
if (newProperties != null)
{
PopulateProperties(overrideValues, properties, newProperties);
}
}
finally
{
if (stream != null)
{
try
{
stream.Close();
}
catch (IOException ex)
{
#region Instrumentation
if (_log.IsWarnEnabled)
{
_log.Warn("Could not close stream from resource " + resource.Description, ex);
}
#endregion
}
}
}
return properties;
}
/// <summary>
/// Read from the specified configuration from the supplied XML
/// <paramref name="document"/> into a
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
/// <remarks>
/// <note>
/// Does <b>not</b> support section grouping. The supplied XML
/// <paramref name="document"/> must already be loaded.
/// </note>
/// </remarks>
/// <param name="document">
/// The <see cref="System.Xml.XmlDocument"/> to read from.
/// </param>
/// <param name="configSectionName">
/// The configuration section name to read.
/// </param>
/// <returns>
/// A newly populated
/// <see cref="System.Collections.Specialized.NameValueCollection"/>.
/// </returns>
/// <exception cref="System.Xml.XmlException">
/// If any errors are encountered while reading (this only applies to
/// v1.1 and greater of the .NET Framework).
/// </exception>
/// <exception cref="System.Exception">
/// If any errors are encountered while reading (this only applies to
/// v1.0 of the .NET Framework).
/// </exception>
/// <exception cref="Spring.Objects.FatalObjectException">
/// If the configuration section was otherwise invalid.
/// </exception>
public static NameValueCollection ReadFromXmlDocument(XmlDocument document,
string configSectionName)
{
// find the config section declaration (if one exists)...
return (NameValueCollection)GetSectionFromXmlDocument(document, configSectionName);
}
/// <summary>
/// Returns the section from the specified resource with the given section name
/// </summary>
public static object GetSection(IResource resource, string configSectionName)
{
using (Stream istm = resource.InputStream)
{
ConfigXmlDocument doc = new ConfigXmlDocument();
doc.Load(istm);
return GetSectionFromXmlDocument(doc, configSectionName);
}
}
#if NET_2_0
/// <summary>
/// Returns the typed section from the specified resource with the given section name
/// </summary>
public static TResult GetSection<TResult>(IResource resource, string configSectionName)
{
using (Stream istm = resource.InputStream)
{
ConfigXmlDocument doc = new ConfigXmlDocument();
doc.Load(istm);
object result = GetSectionFromXmlDocument(doc, configSectionName);
if (result != null && !(result is TResult))
{
throw new ArgumentException(string.Format("evaluating configuration sectoin {0} does not result in an instance of type {1}", configSectionName, typeof(TResult)));
}
return (TResult)result;
}
}
/// <summary>
/// Returns the typed result of evaluating the specified <paramref name="configSectionName"/>.
/// </summary>
/// <exception cref="ArgumentException">if the result's type does not match the expected type</exception>
public static TResult GetSectionFromXmlDocument<TResult>(XmlDocument configDocument, string configSectionName)
{
object result = GetSectionFromXmlDocument(configDocument, configSectionName);
if (result != null && !(result is TResult))
{
throw new ArgumentException(string.Format("evaluating configuration sectoin {0} does not result in an instance of type {1}", configSectionName, typeof(TResult)));
}
return (TResult)result;
}
#endif
/// <summary>
/// Reads the specified configuration section from the given <see cref="XmlDocument"/>
/// </summary>
/// <param name="document"></param>
/// <param name="configSectionName"></param>
/// <returns></returns>
public static object GetSectionFromXmlDocument(XmlDocument document, string configSectionName)
{
string[] sectionNameParts = configSectionName.Split('/');
string sectionHandlerPath = string.Format("//{0}/{1}", ConfigurationElement, ConfigSectionsElement);
if (sectionNameParts.Length > 1)
{
// deal with sectionGroups
for (int i = 0; i < sectionNameParts.Length - 1; i++)
{
sectionHandlerPath = string.Format("{0}/{1}[@{2}='{3}']", sectionHandlerPath, ConfigSectionGroupElement, ConfigSectionNameAttribute, sectionNameParts[i]);
}
}
sectionHandlerPath = string.Format("{0}/{1}[@{2}='{3}']", sectionHandlerPath, ConfigSectionElement, ConfigSectionNameAttribute, sectionNameParts[sectionNameParts.Length - 1]);
XmlNode xmlConfig = document.SelectSingleNode(sectionHandlerPath);
// create appropriate configuration section handler...
Type handlerType = null;
if (xmlConfig == null)
{
// none specified, use machine inherited
XmlDocument machineConfig = new XmlDocument();
machineConfig.Load(RuntimeEnvironment.SystemConfigurationFile);
xmlConfig = machineConfig.SelectSingleNode(sectionHandlerPath);
if (xmlConfig == null)
{
// TOOD: better throw a sensible exception in case of a missing handler configuration?
handlerType = typeof(NameValueFileSectionHandler);
}
}
if (xmlConfig != null)
{
XmlAttribute xmlConfigType = xmlConfig.Attributes[ConfigSectionTypeAttribute];
handlerType = TypeResolutionUtils.ResolveType(xmlConfigType.Value);
}
if (handlerType == null)
{
throw new ConfigurationException(string.Format("missing 'type' attribute on section definition for '{0}'", configSectionName));
}
// obtain Xml node with section content
XmlNode sectionContent = document.SelectSingleNode(string.Format("//{0}/{1}", ConfigurationElement, configSectionName));
if (sectionContent == null)
{
throw ConfigurationUtils.CreateConfigurationException("Cannot read properties; config section '" + configSectionName + "' not found.");
}
// IConfigurationSectionHandler
if (typeof(IConfigurationSectionHandler).IsAssignableFrom(handlerType))
{
IConfigurationSectionHandler handler = (IConfigurationSectionHandler)ObjectUtils.InstantiateType(handlerType);
return ((IConfigurationSectionHandler)handler).Create(null, null, sectionContent);
}
#if !NET_1_0 && !NET_1_1
// NET 2.0 ConfigurationSection
if (typeof(ConfigurationSection).IsAssignableFrom(handlerType))
{
ConfigurationSection section = CreateConfigurationSection(handlerType, new XmlNodeReader(sectionContent));
return section;
}
#endif
// Not supported
throw ConfigurationUtils.CreateConfigurationException("Configuration section '" + configSectionName + "' is neither of type IConfigurationSectionHandler nor ConfigurationSection.");
}
#if !NET_1_0 && !NET_1_1
private delegate void DeserializeSectionMethod(ConfigurationSection section, XmlReader reader);
private static DeserializeSectionMethod deserialized = (DeserializeSectionMethod)Delegate.CreateDelegate(typeof(DeserializeSectionMethod),
typeof(ConfigurationSection).GetMethod("DeserializeSection",
BindingFlags.Instance |
BindingFlags.NonPublic));
private static ConfigurationSection CreateConfigurationSection(Type handlerType, XmlReader reader)
{
ConfigurationSection section = (ConfigurationSection)ObjectUtils.InstantiateType(handlerType);
deserialized(section, reader);
return section;
}
#endif
/// <summary>
/// Populates the supplied <paramref name="properties"/> with values from
/// a .NET application configuration file.
/// </summary>
/// <param name="properties">
/// The <see cref="System.Collections.Specialized.NameValueCollection"/>
/// to add any key-value pairs to.
/// </param>
/// <param name="configSectionName">
/// The configuration section name in the a .NET application configuration
/// file.
/// </param>
/// <param name="overrideValues">
/// If a key already exists, is its value to be appended to the current
/// value or replaced?
/// </param>
/// <returns>
/// <see langword="true"/> if the supplied
/// <paramref name="configSectionName"/> was found.
/// </returns>
public static bool PopulateFromAppConfig(
NameValueCollection properties, string configSectionName, bool overrideValues)
{
bool sectionFound = false;
NameValueCollection newProperties
= ConfigurationUtils.GetSection(configSectionName) as NameValueCollection;
if (newProperties != null)
{
sectionFound = true;
PopulateProperties(overrideValues, properties, newProperties);
}
return sectionFound;
}
private static void PopulateProperties(
bool overrideValues, NameValueCollection properties, NameValueCollection newProperties)
{
if (!overrideValues)
{
properties.Add(newProperties);
}
else
{
foreach (string key in newProperties.AllKeys)
{
properties.Set(key, newProperties.Get(key));
}
}
}
#region Constructor (s) / Destructor
// CLOVER:OFF
/// <summary>
/// Creates a new instance of the ConfigurationReader class.
/// </summary>
/// <remarks>
/// <p>
/// This is a utility class, and as such has no publicly visible
/// constructors.
/// </p>
/// </remarks>
private ConfigurationReader()
{
}
// CLOVER:ON
#endregion
}
}

View File

@@ -1008,6 +1008,7 @@
<Compile Include="Util\ConfigXmlDocument.cs" />
<Compile Include="Util\ConfigXmlElement.cs" />
<Compile Include="Util\FatalReflectionException.cs" />
<Compile Include="Util\IChainableConfigSystem.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\ITextPosition.cs" />
<Compile Include="Util\ObjectUtils.cs" />

View File

@@ -22,6 +22,7 @@
using System;
using System.Configuration;
using System.Reflection;
using System.Xml;
#endregion
@@ -34,6 +35,12 @@ namespace Spring.Util
/// <author>Aleksandar Seovic</author>
public class ConfigurationUtils
{
/// <summary>
/// Avoid BeforeFieldInit pitfall
/// </summary>
static ConfigurationUtils()
{}
/// <summary>
/// Parses the configuration section.
/// </summary>
@@ -161,7 +168,7 @@ namespace Spring.Util
/// <returns>Configuration exception.</returns>
public static Exception CreateConfigurationException(string message)
{
return CreateConfigurationException(message, (Exception) null);
return CreateConfigurationException(message, (Exception)null);
}
/// <summary>
@@ -170,7 +177,7 @@ namespace Spring.Util
/// <returns>Configuration exception.</returns>
public static Exception CreateConfigurationException()
{
return CreateConfigurationException(null, (Exception) null);
return CreateConfigurationException(null, (Exception)null);
}
/// <summary>
@@ -225,5 +232,55 @@ namespace Spring.Util
#endif
}
#if NET_2_0
/// <summary>
/// Sets the current <see cref="System.Configuration.Internal.IInternalConfigSystem"/> to be used by <see cref="ConfigurationManager"/>.
/// </summary>
/// <remarks>
/// <20>f <paramref name="configSystem"/> implements <see cref="IChainableConfigSystem"/>, this method invokes
/// <see cref="IChainableConfigSystem.SetInnerConfigurationSystem"/> on the new configSystem to chain them.<br/>
/// <b> Note, that this method requires reflection on internals of <see cref="ConfigurationManager"/></b>
/// </remarks>
/// <param name="configSystem">the configuration system to set</param>
/// <param name="enforce">bypasses the check if the current system has already been initialized</param>
/// <returns>the previous config system, if any</returns>
public static System.Configuration.Internal.IInternalConfigSystem SetConfigurationSystem(System.Configuration.Internal.IInternalConfigSystem configSystem, bool enforce)
{
FieldInfo s_configSystem = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.Static | BindingFlags.NonPublic);
System.Configuration.Internal.IInternalConfigSystem innerConfigSystem = (System.Configuration.Internal.IInternalConfigSystem)s_configSystem.GetValue(null);
if (configSystem is IChainableConfigSystem)
{
((IChainableConfigSystem)configSystem).SetInnerConfigurationSystem(innerConfigSystem);
}
try
{
setConfigurationSystem(configSystem, true);
}
catch (InvalidOperationException)
{
if (!enforce)
{
throw;
}
s_configSystem.SetValue(null, configSystem);
}
return innerConfigSystem;
}
private static T CreateDelegate<T>(MethodInfo method)
{
return (T)(object)Delegate.CreateDelegate(typeof(T), method);
}
private delegate void SetConfigurationSystemHandler(System.Configuration.Internal.IInternalConfigSystem configSystem, bool setComplete);
private static SetConfigurationSystemHandler setConfigurationSystem =
CreateDelegate<SetConfigurationSystemHandler>(typeof(ConfigurationManager).GetMethod("SetConfigurationSystem"
, BindingFlags.Static | BindingFlags.NonPublic));
#endif
}
}

View File

@@ -0,0 +1,39 @@
#region License
/*
* Copyright 2002-2009 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
namespace Spring.Util
{
#if NET_2_0
using System.Configuration.Internal;
/// <summary>
/// Implement this interface to create your own, delegating <see cref="IInternalConfigSystem"/>
/// and set them using <see cref="ConfigurationUtils.SetConfigurationSystem"/>
/// </summary>
public interface IChainableConfigSystem : IInternalConfigSystem
{
/// <summary>
///
/// </summary>
/// <param name="innerConfigSystem"></param>
void SetInnerConfigurationSystem(IInternalConfigSystem innerConfigSystem);
}
#endif
}

View File

@@ -38,7 +38,7 @@ using Spring.Util;
namespace Spring.EnterpriseServices
{
/// <summary>
/// Exports specified components as ServicedComponents.
/// Exports components as ServicedComponents using the specified <see cref="ServicedComponentExporter"/>s.
/// </summary>
/// <remarks>
/// <para>

View File

@@ -0,0 +1,156 @@
#region License
/*
* Copyright 2002-2009 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
namespace Spring.EnterpriseServices
{
#if NET_2_0
using System;
using System.Configuration;
using System.Reflection;
using System.Xml;
using Spring.Core.TypeResolution;
using Spring.Util;
using System.Configuration.Internal;
/// <summary>
/// SUBJECT TO CHANGE -FOR INTERNAL USE ONLY!<br/>
/// Holds configuration information from a given configuration file, obtained by <see cref="ConfigurationManager.OpenExeConfiguration(string)"/>.
/// You may use <see cref="ConfigurationUtils.SetConfigurationSystem"/> to replace the active configuration system.
/// </summary>
/// <seealso cref="ConfigurationManager.OpenExeConfiguration(string)"/>
/// <seealso cref="ConfigurationUtils.SetConfigurationSystem"/>
public class ExeConfigurationSystem : IChainableConfigSystem
{
private string _configPath;
private Configuration _configuration;
private IInternalConfigSystem _next;
/// <summary>
/// initializes this instance with a path to be passed into <see cref="ConfigurationManager.OpenExeConfiguration(string)"/>
/// </summary>
/// <param name="configPath"></param>
public ExeConfigurationSystem(string configPath)
{
_configPath = configPath;
}
/// <summary>
/// Purges cached configuration
/// </summary>
public void RefreshConfig(string sectionName)
{
if (_next != null)
{
_next.RefreshConfig(sectionName);
}
_configuration = null;
}
///<summary>
/// Only true if the underlying config system supports this.
///</summary>
public bool SupportsUserConfig
{
get
{
EnsureInit();
if (_next != null)
{
return _next.SupportsUserConfig;
}
return false;
}
}
/// <summary>
/// Set the nested configuration system to delegate calls in case we can't resolve a config section ourselves
/// </summary>
public void SetInnerConfigurationSystem(IInternalConfigSystem innerConfigSystem)
{
_next = innerConfigSystem;
}
private void EnsureInit()
{
if (_configuration == null)
{
lock (this)
{
if (_configuration == null)
{
_configuration = ConfigurationManager.OpenExeConfiguration(_configPath);
}
}
}
}
private delegate object ResolveSectionRuntimeObject(ConfigurationSection section);
private static ResolveSectionRuntimeObject resolveSectionRuntimeObject =
(ResolveSectionRuntimeObject)Delegate.CreateDelegate(typeof(ResolveSectionRuntimeObject),
typeof (ConfigurationSection).GetMethod("GetRuntimeObject",
BindingFlags.Instance |
BindingFlags.NonPublic));
/// <summary>
/// Get the specified section
/// </summary>
/// <param name="sectionName"></param>
/// <returns></returns>
public object GetSection(string sectionName)
{
EnsureInit();
ConfigurationSection thisSection = _configuration.GetSection(sectionName);
object parent = null;
if (_next != null)
{
parent = _next.GetSection(sectionName);
}
if (thisSection == null)
{
return parent;
}
object result = resolveSectionRuntimeObject(thisSection);
if (result is DefaultSection)
{
string rawXml = thisSection.SectionInformation.GetRawXml();
if (string.IsNullOrEmpty(rawXml))
{
return null;
}
Type t = TypeResolutionUtils.ResolveType(thisSection.SectionInformation.Type);
if (typeof(IConfigurationSectionHandler).IsAssignableFrom(t))
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(thisSection.SectionInformation.GetRawXml());
IConfigurationSectionHandler handler = (IConfigurationSectionHandler) Activator.CreateInstance(t);
return handler.Create(parent, null, xmlDoc.DocumentElement );
}
throw new ConfigurationErrorsException(string.Format("missing <section> declaration for section '{0}'", sectionName));
}
return result;
}
}
#endif
}

View File

@@ -23,11 +23,17 @@
#region Imports
using System;
using System.Configuration;
using System.Diagnostics;
using System.EnterpriseServices;
using System.IO;
using System.Reflection;
using System.Xml;
using Spring.Context;
using Spring.Context.Support;
using Spring.Core.IO;
using Spring.Objects.Factory.Config;
using Spring.Util;
using ConfigXmlDocument = Spring.Util.ConfigXmlDocument;
#endregion
@@ -43,6 +49,7 @@ namespace Spring.EnterpriseServices
{
private static bool isInitialized;
private static string componentDirectory;
private static IApplicationContext _appContext;
static ServicedComponentHelper()
{
@@ -60,6 +67,7 @@ namespace Spring.EnterpriseServices
lock (typeof(ServicedComponentHelper))
{
if (isInitialized) return;
isInitialized = true;
// this is to ensure, that assemblies placed next to the component assembly can be loaded
@@ -70,26 +78,56 @@ namespace Spring.EnterpriseServices
// switch to component assembly's directory (affects resolving relative paths during context instantiation!)
Environment.CurrentDirectory = componentDirectory;
// read in config file if any
FileInfo configFile = new FileInfo(componentAssemblyFile.FullName + ".spring-context.xml");
FileInfo configFile = new FileInfo(componentAssemblyFile.FullName);
if (configFile.Exists)
{
ConfigXmlDocument configDoc = new ConfigXmlDocument();
configDoc.Load(configFile.FullName);
XmlNode configNode = configDoc.SelectSingleNode("//context");
ServicedComponentContextHandler handler = new ServicedComponentContextHandler();
lock (ContextRegistry.SyncRoot)
bool isRunningOutOfProcess = IsRunningOutOfProcess();
#if NET_2_0
ExeConfigurationSystem comConfig = new ExeConfigurationSystem(configFile.FullName);
if (isRunningOutOfProcess)
{
// it might accidentially have happend, that the contextregistry has already
// been initialized using the client application's app.config configuration.
// Most of the time this doesn't make sense to read a configuration from a
// different AppDomain, thus we read in our own config file.
ContextRegistry.Clear();
handler.Create(null, null, configNode);
Trace.WriteLine(string.Format("configuring COM OutProc Server '{0}' using '{1}'", componentAssemblyFile.FullName, componentAssemblyFile.FullName + ".config"));
// make the config "global"
ConfigurationUtils.SetConfigurationSystem(comConfig, true);
_appContext = ContextRegistry.GetContext();
if (_appContext == null)
{
throw ConfigurationUtils.CreateConfigurationException("Spring-exported COM components require <spring/context> section");
}
}
else
{
Trace.WriteLine(string.Format("configuring COM InProc Server '{0}' using section <spring/context> from file '{1}'", componentAssemblyFile.FullName, componentAssemblyFile.FullName + ".config"));
_appContext = (IApplicationContext)comConfig.GetSection("spring/context");
if (_appContext == null)
{
throw ConfigurationUtils.CreateConfigurationException("Spring-exported COM components require <spring/context> section in configuration file");
}
}
#else
_appContext = (IApplicationContext) ConfigurationReader.GetSection(new FileSystemResource(configFile.FullName + ".config"),"spring/context");
if (_appContext == null)
{
throw ConfigurationUtils.CreateConfigurationException("Spring-exported COM components require <spring/context> section in configuration file");
}
#endif
}
else
{
Trace.WriteLine(string.Format("No configuration file '{0}' for COM component '{1}' found - bypassing configuration", componentAssemblyFile.FullName + ".config", componentAssemblyFile.FullName));
}
}
}
private static bool IsRunningOutOfProcess()
{
// TODO: checkout a prob. better way to find out, whether we are executing as a com server or library
return AppDomain.CurrentDomain.SetupInformation.ApplicationName == "dllhost.exe";
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string name = args.Name.Split(',')[0];
@@ -104,7 +142,11 @@ namespace Spring.EnterpriseServices
public static object GetObject(ServicedComponent sender, string targetName)
{
EnsureComponentContextRegistryInitialized(sender.GetType());
return ContextRegistry.GetContext().GetObject(targetName);
if (_appContext == null)
{
throw ConfigurationUtils.CreateConfigurationException("Spring-exported COM components require <spring/context> section in configuration file");
}
return _appContext.GetObject(targetName);
}
}
}

View File

@@ -78,6 +78,7 @@
<Reference Include="System">
<Name>System</Name>
</Reference>
<Reference Include="System.configuration" />
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
@@ -98,6 +99,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="EnterpriseServices\ExeConfigurationSystem.cs" />
<Compile Include="EnterpriseServices\EnterpriseServicesExporter.cs" />
<Compile Include="EnterpriseServices\ServicedComponentContextHandler.cs" />
<Compile Include="EnterpriseServices\ServicedComponentExporter.cs" />

View File

@@ -20,9 +20,11 @@
#region Imports
using System;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using NUnit.Framework;
@@ -45,102 +47,182 @@ namespace Spring.Objects.Factory.Config
<configSections>
<section name='foo' type='System.Configuration.NameValueSectionHandler, System'/>
</configSections>
<foo>
<add key='rilo' value='kiley'/>
<add key='jenny' value='lewis'/>
</foo>
<foo>
<add key='rilo' value='kiley'/>
<add key='jenny' value='lewis'/>
</foo>
</configuration>";
#if !NET_0 && !NET_1_1
/// <summary>
/// Unfortunately ConfigurationManager doesn't accept uri's.
/// </summary>
[Test]
public void ConfigurationManagerCannotReadFromUrl()
{
try
{
ConfigurationManager.OpenExeConfiguration("http://localhost/something.config");
Assert.Fail();
}
catch (ConfigurationErrorsException cfgex)
{
Assert.IsInstanceOfType(typeof (ArgumentException), cfgex.InnerException);
}
}
#endif
[Test]
public void ReadSunnyDay()
{
new StreamHelperDecorator(new StreamHelperCallback(_ReadSunnyDay)).Run();
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml)))
{
NameValueCollection props = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo");
Assert.IsNotNull(props,
"Failed to read in any properties at all (props is null).");
Assert.AreEqual(2, props.Count,
"Wrong number of properties read in.");
Assert.AreEqual("kiley",
props["rilo"],
"Wrong value for second property");
Assert.AreEqual("lewis",
props["jenny"],
"Wrong value for second property");
}
string machineConfig = RuntimeEnvironment.SystemConfigurationFile;
}
private void _ReadSunnyDay(out Stream stream)
#if !NET_1_0 && !NET_1_1
[Test]
public void GetSectionLocalSectionHandler()
{
stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml));
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo");
Assert.IsNotNull(props, "Failed to read in any properties at all (props is null).");
Assert.AreEqual(2, props.Count, "Wrong number of properties read in.");
Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property");
Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property");
string xml = @"<?xml version='1.0' encoding='UTF-8' ?>
<configuration>
<configSections>
<section name='connectionStrings' type='System.Configuration.ConnectionStringsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' requirePermission='false' />
</configSections>
<connectionStrings>
<add name='Sales'
providerName='System.Data.SqlClient'
connectionString= 'server=myserver;database=Products;uid=user name;pwd=secure password' />
</connectionStrings>
</configuration>
";
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
ConnectionStringsSection css = ConfigurationReader.GetSection<ConnectionStringsSection>(new InputStreamResource(stream, ""), "connectionStrings");
Assert.IsNotNull(css, "Failed to read in any properties at all (props is null).");
Assert.IsNotNull(css.ConnectionStrings["Sales"]);
Assert.AreEqual("System.Data.SqlClient", css.ConnectionStrings["Sales"].ProviderName);
Assert.AreEqual("server=myserver;database=Products;uid=user name;pwd=secure password", css.ConnectionStrings["Sales"].ConnectionString);
}
}
[Test]
public void GetSectionMachineInheritedSectionHandler()
{
string xml = @"<?xml version='1.0' encoding='UTF-8' ?>
<configuration>
<connectionStrings>
<add name='Sales'
providerName='System.Data.SqlClient'
connectionString= 'server=myserver;database=Products;uid=user name;pwd=secure password' />
</connectionStrings>
</configuration>
";
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
ConnectionStringsSection css = ConfigurationReader.GetSection<ConnectionStringsSection>(new InputStreamResource(stream, ""), "connectionStrings");
Assert.IsNotNull(css, "Failed to read in any properties at all (props is null).");
Assert.IsNotNull(css.ConnectionStrings["Sales"]);
Assert.AreEqual("System.Data.SqlClient", css.ConnectionStrings["Sales"].ProviderName);
Assert.AreEqual("server=myserver;database=Products;uid=user name;pwd=secure password", css.ConnectionStrings["Sales"].ConnectionString);
}
}
#endif
[Test]
public void GetSectionSunnyDay()
{
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml)))
{
NameValueCollection props = ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo");
Assert.IsNotNull(props,
"Failed to read in any properties at all (props is null).");
Assert.AreEqual(2, props.Count,
"Wrong number of properties read in.");
Assert.AreEqual("kiley",
props["rilo"],
"Wrong value for second property");
Assert.AreEqual("lewis",
props["jenny"],
"Wrong value for second property");
}
}
[Test]
public void ReadWithOverrideOfPreviouslyExistingValues()
{
new StreamHelperDecorator(new StreamHelperCallback(_ReadWithOverrideOfPreviouslyExistingValues)).Run();
}
private void _ReadWithOverrideOfPreviouslyExistingValues(out Stream stream)
{
stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml));
NameValueCollection defaults = new NameValueCollection();
defaults.Add("jenny", "agutter");
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", defaults);
Assert.IsTrue(ReferenceEquals(defaults, props), "Must have got same collection as was passed in.");
Assert.AreEqual("lewis", props["jenny"], "Wrong value for overridden property (was not overridden");
using(Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml)))
{
NameValueCollection defaults = new NameValueCollection();
defaults.Add("jenny", "agutter");
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", defaults);
Assert.IsTrue(ReferenceEquals(defaults, props), "Must have got same collection as was passed in.");
Assert.AreEqual("lewis", props["jenny"], "Wrong value for overridden property (was not overridden");
}
}
[Test]
public void ReadWithOverrideOfPreviouslyExistingValuesButWithOverrideSwitchedOff()
{
new StreamHelperDecorator(new StreamHelperCallback(_ReadWithOverrideOfPreviouslyExistingValuesButWithOverrideSwitchedOff)).Run();
}
private void _ReadWithOverrideOfPreviouslyExistingValuesButWithOverrideSwitchedOff(out Stream stream)
{
stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml));
NameValueCollection defaults = new NameValueCollection();
defaults.Add("jenny", "agutter");
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", defaults, false);
Assert.IsTrue(ReferenceEquals(defaults, props), "Must have got same collection as was passed in.");
Assert.AreEqual("agutter,lewis", props["jenny"], "Wrong value for overridden property (was not overridden");
using(Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml)))
{
NameValueCollection defaults = new NameValueCollection();
defaults.Add("jenny", "agutter");
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", defaults, false);
Assert.IsTrue(ReferenceEquals(defaults, props), "Must have got same collection as was passed in.");
Assert.AreEqual("agutter,lewis", props["jenny"], "Wrong value for overridden property (was not overridden");
}
}
[Test]
public void ReadWithNullExistingValuesPassedIn()
{
new StreamHelperDecorator(new StreamHelperCallback(_ReadWithNullExistingValuesPassedIn)).Run();
}
private void _ReadWithNullExistingValuesPassedIn(out Stream stream)
{
stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml));
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", null);
Assert.IsNotNull(props, "Failed to read in any properties at all (props is null).");
Assert.AreEqual(2, props.Count, "Wrong number of properties read in.");
Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property");
Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property");
using(Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml)))
{
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", null);
Assert.IsNotNull(props, "Failed to read in any properties at all (props is null).");
Assert.AreEqual(2, props.Count, "Wrong number of properties read in.");
Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property");
Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property");
}
}
[Test]
public void ReadWithNoConfigSectionSectionDefaultsToNameValueSectionHandler()
{
new StreamHelperDecorator(new StreamHelperCallback(_ReadWithNoConfigSectionSectionDefaultsToNameValueSectionHandler)).Run();
}
private void _ReadWithNoConfigSectionSectionDefaultsToNameValueSectionHandler(out Stream stream)
{
const string NoConfigSectionXml = @"<?xml version='1.0' encoding='UTF-8' ?>
<configuration>
<foo>
<add key='rilo' value='kiley'/>
<add key='jenny' value='lewis'/>
</foo>
<foo>
<add key='rilo' value='kiley'/>
<add key='jenny' value='lewis'/>
</foo>
</configuration>";
stream = new MemoryStream(Encoding.UTF8.GetBytes(NoConfigSectionXml));
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", null);
Assert.IsNotNull(props, "Failed to read in any properties at all (props is null).");
Assert.AreEqual(2, props.Count, "Wrong number of properties read in.");
Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property");
Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property");
using(Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(NoConfigSectionXml)))
{
NameValueCollection props
= ConfigurationReader.Read(new InputStreamResource(stream, ""), "foo", null);
Assert.IsNotNull(props, "Failed to read in any properties at all (props is null).");
Assert.AreEqual(2, props.Count, "Wrong number of properties read in.");
Assert.AreEqual("kiley", props["rilo"], "Wrong value for second property");
Assert.AreEqual("lewis", props["jenny"], "Wrong value for second property");
}
}
[Test]
@@ -148,16 +230,13 @@ namespace Spring.Objects.Factory.Config
[ExpectedException(typeof(ConfigurationException), "Cannot read properties; config section 'ELNOMBRE' not found.")]
#else
[ExpectedException(typeof(ConfigurationErrorsException), "Cannot read properties; config section 'ELNOMBRE' not found.")]
#endif
#endif
public void TryReadFromNonExistantConfigSection()
{
new StreamHelperDecorator(new StreamHelperCallback(_TryReadFromNonExistantConfigSection)).Run();
}
private void _TryReadFromNonExistantConfigSection(out Stream stream)
{
stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml));
ConfigurationReader.Read(new InputStreamResource(stream, ""), "ELNOMBRE", null);
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(SunnyDayXml)))
{
ConfigurationReader.Read(new InputStreamResource(stream, ""), "ELNOMBRE", null);
}
}
}
}

View File

@@ -14,7 +14,13 @@ namespace Spring
/// Supports obtaining embedded resources from assembly.
/// </summary>
/// <remarks>
/// <para>
/// The first <c>context</c> argument is always the namespace scope to be used for resolving resource names.
/// </para>
/// <para>
/// Upon first usage, TestResourceLoader registers the "testres://" protocol prefix for loading embedded resources.
/// A testres:// Url must be of the form "testres://./&lt;context-typename&gt;#&lt;ext" - <see cref="GetStream"/>.
/// </para>
/// </remarks>
public class TestResourceLoader
{
@@ -73,6 +79,12 @@ namespace Spring
private TestResourceLoader()
{ }
/// <summary>
/// Returns an Uri of the form "testres://./resourcname" that may be passed into <see cref="WebRequest.Create(string)"/> etc.
/// </summary>
/// <param name="context"></param>
/// <param name="ext"></param>
/// <returns></returns>
public static Uri GetUri(object context, string ext)
{
string resname = context.GetType().AssemblyQualifiedName + "#" + ext;
@@ -131,6 +143,10 @@ namespace Spring
}
}
/// <summary>
/// Returns an embedded assembly resource, who's name is constructed from the given parameters as
/// <c>context.GetType().FullName + ext</c>
/// </summary>
public static Stream GetStream(object context, string ext)
{
Type contextType = (context is Type) ? (Type)context : context.GetType();
@@ -140,6 +156,32 @@ namespace Spring
return stm;
}
/// <summary>
/// Exports a resource obtained via <see cref="GetStream"/> to the specified destination.
/// </summary>
public static FileInfo ExportResource(object context, string ext, FileInfo destination)
{
Stream istm = GetStream(context, ext);
using(istm)
{
FileStream ostm = destination.OpenWrite();
using (ostm)
{
byte[] buffer = new byte[2048];
int bytesRead = istm.Read(buffer, 0, buffer.Length);
while (bytesRead > 0)
{
ostm.Write(buffer, 0, bytesRead);
bytesRead = istm.Read(buffer, 0, buffer.Length);
}
ostm.Flush();
ostm.Close();
}
istm.Close();
}
return destination;
}
/// <summary>
/// returns an "assembly://" uri for the specified manifest resource, scoped by the namespace of the specified type.
/// ("assembly://hint.assemblyname_without_version/hint.Namespace/name")

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
</sectionGroup>
<sectionGroup name="common">
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
</sectionGroup>
</configSections>
<appSettings>
<add key="key" value="from custom config!"/>
</appSettings>
<common>
<logging>
<factoryAdapter type="Common.Logging.Simple.TraceLoggerFactoryAdapter, Common.Logging"/>
</logging>
</common>
</configuration>

View File

@@ -0,0 +1,45 @@

namespace Spring.EnterpriseServices
{
#if NET_2_0
using System.Configuration;
using System.Configuration.Internal;
using System.IO;
using Common.Logging;
using Common.Logging.Simple;
using NUnit.Framework;
using Spring.Util;
[TestFixture]
public class ExeConfigurationSystemTests
{
[Test]
public void SunnyDay()
{
FileInfo resFile = TestResourceLoader.ExportResource(this, ".config", new FileInfo(Path.GetTempFileName()+".config"));
string exePath = resFile.FullName.Substring(0, resFile.FullName.Length - ".config".Length);
Assert.IsTrue(resFile.Exists);
IInternalConfigSystem prevConfig = null;
try
{
ExeConfigurationSystem ccs = new ExeConfigurationSystem(exePath);
prevConfig = ConfigurationUtils.SetConfigurationSystem(ccs, true);
LogSetting settings = (LogSetting) ConfigurationManager.GetSection("common/logging");
Assert.AreEqual(typeof (TraceLoggerFactoryAdapter), settings.FactoryAdapterType);
Assert.AreEqual("from custom config!", ConfigurationManager.AppSettings["key"]);
Assert.IsNull(ConfigurationManager.GetSection("spring/context"));
}
finally
{
if (prevConfig != null)
{
ConfigurationUtils.SetConfigurationSystem(prevConfig, true);
}
resFile.Delete();
}
}
}
#endif
}

View File

@@ -111,7 +111,7 @@ namespace Spring.EnterpriseServices
try
{
// ServiceComponent will obtain its target from root context
ContextRegistry.RegisterContext(appCtx);
// ContextRegistry.RegisterContext(appCtx);
IComparable testObject;
testObject = (IComparable)Activator.CreateInstance(serviceType);
@@ -126,6 +126,7 @@ namespace Spring.EnterpriseServices
}
}
#if NET_2_0
[Test]
public void CanExportAopProxyToServer()
{
@@ -146,9 +147,9 @@ namespace Spring.EnterpriseServices
finally
{
exporter.UnregisterServicedComponents(assemblyFile);
ContextRegistry.Clear();
}
}
#endif
private Type ExportObject(EnterpriseServicesExporter exporter, FileInfo assemblyFile, IConfigurableApplicationContext appCtx, string objectName)
{

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<!-- library components access their process' app.config -->
<resource uri="ServiceComponentExporterTests.TestServicedComponents.Services.xml" />
</context>
</spring>
</configuration>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
<sectionGroup name="common">
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
</sectionGroup>
</configSections>
<common>
<logging>
<factoryAdapter type="Common.Logging.Simple.TraceLoggerFactoryAdapter, Common.Logging"/>
</logging>
</common>
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object id="countingInterceptor" type="Spring.EnterpriseServices.ServicedComponentExporterTests+CountingMethodInterceptor, Spring.Services.Tests" />
<object name="objectTest" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="ProxyInterfaces">
<list>
<value>System.IComparable</value>
</list>
</property>
<property name="InterceptorNames">
<list>
<idref local="countingInterceptor"/>
</list>
</property>
</object>
</objects>
</spring>
</configuration>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<spring>
<context>
<resource uri="ServiceComponentExporterTests.TestServicedComponents.Services.xml" />
</context>
</spring>

View File

@@ -72,6 +72,14 @@
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="antlr.runtime, Version=2.7.6.2, Culture=neutral, PublicKeyToken=65e474d141e25e07, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\antlr.runtime.dll</HintPath>
</Reference>
<Reference Include="Common.Logging, Version=1.2.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\Common.Logging.dll</HintPath>
</Reference>
<Reference Include="DotNetMock, Version=0.7.4.0, Culture=neutral, PublicKeyToken=805ea88df19095f6">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\DotNetMock.dll</HintPath>
@@ -87,6 +95,7 @@
<Reference Include="System">
<Name>System</Name>
</Reference>
<Reference Include="System.configuration" />
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
@@ -103,6 +112,8 @@
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="EnterpriseServices\ExeConfigurationSystemTests.cs" />
<Compile Include="EnterpriseServices\ExportedServicedComponentSample.cs" />
<Compile Include="EnterpriseServices\ServicedComponentExporterTests.cs" />
<Compile Include="Remoting\BaseRemotingTestFixture.cs" />
<Compile Include="Remoting\CaoExporterTests.cs">
@@ -138,6 +149,7 @@
</SubType>
</None>
<None Include="Data\Spring\Web\Services\Service.cs.fyi" />
<EmbeddedResource Include="EnterpriseServices\ExeConfigurationSystemTests.config" />
<None Include="Spring.Services.Tests.build" />
<None Include="Spring.Services.Tests.dll.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -190,9 +202,12 @@
<EmbeddedResource Include="Data\Spring\Remoting\saoSingleton-autowired.xml" />
</ItemGroup>
<ItemGroup>
<Content Include="ServiceComponentExporterTests.TestServicedComponents.exe.spring-context.xml">
<None Include="ServiceComponentExporterTests.TestServicedComponents.dll.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</None>
<None Include="ServiceComponentExporterTests.TestServicedComponents.exe.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Content Include="ServiceComponentExporterTests.TestServicedComponents.Services.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>