From 3f5e444acbaa6615b22f10b83f5e046b8880ae3c Mon Sep 17 00:00:00 2001 From: Suha Can Date: Tue, 1 Mar 2011 17:23:02 -0800 Subject: [PATCH 01/11] Creating a separate branch for contributions. --HG-- branch : contributions From 556be00e5d6c58a6c07c10f2236cca92c03ef672 Mon Sep 17 00:00:00 2001 From: attilah Date: Tue, 8 Mar 2011 22:30:26 +0100 Subject: [PATCH 02/11] Fixed: #17453 - Logging module (Log4net initialization) is throwing exceptions in Medium Trust --HG-- branch : contributions --- src/Orchard/Logging/LoggingModule.cs | 2 +- src/Orchard/Logging/OrchardLog4netFactory.cs | 58 ++ src/Orchard/Logging/OrchardLog4netLogger.cs | 347 +++++++ src/Orchard/Logging/OrchardXmlConfigurator.cs | 325 +++++++ .../OrchardXmlHierarchyConfigurator.cs | 902 ++++++++++++++++++ src/Orchard/Orchard.Framework.csproj | 4 + 6 files changed, 1637 insertions(+), 1 deletion(-) create mode 100644 src/Orchard/Logging/OrchardLog4netFactory.cs create mode 100644 src/Orchard/Logging/OrchardLog4netLogger.cs create mode 100644 src/Orchard/Logging/OrchardXmlConfigurator.cs create mode 100644 src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs diff --git a/src/Orchard/Logging/LoggingModule.cs b/src/Orchard/Logging/LoggingModule.cs index 559458f19..c1e3f2228 100644 --- a/src/Orchard/Logging/LoggingModule.cs +++ b/src/Orchard/Logging/LoggingModule.cs @@ -20,7 +20,7 @@ namespace Orchard.Logging { protected override void Load(ContainerBuilder moduleBuilder) { // by default, use Orchard's logger that delegates to Castle's logger factory moduleBuilder.RegisterType().As().InstancePerLifetimeScope(); - moduleBuilder.RegisterType().As().InstancePerLifetimeScope(); + moduleBuilder.RegisterType().As().InstancePerLifetimeScope(); // call CreateLogger in response to the request for an ILogger implementation moduleBuilder.Register(CreateLogger).As().InstancePerDependency(); diff --git a/src/Orchard/Logging/OrchardLog4netFactory.cs b/src/Orchard/Logging/OrchardLog4netFactory.cs new file mode 100644 index 000000000..5ab8c209d --- /dev/null +++ b/src/Orchard/Logging/OrchardLog4netFactory.cs @@ -0,0 +1,58 @@ +using System; +using System.Configuration; +using System.IO; +using System.Web; +using System.Web.Hosting; + +using Castle.Core.Logging; +using Castle.Services.Logging.Log4netIntegration; + +using log4net; +using log4net.Config; + +using Orchard.Environment.Extensions.Helpers; + +namespace Orchard.Logging { + public class OrchardLog4netFactory : AbstractLoggerFactory { + public OrchardLog4netFactory() + : this(ConfigurationManager.AppSettings["log4net.Config"]) { + } + + public OrchardLog4netFactory(String configFilename) { + if (!String.IsNullOrWhiteSpace(configFilename)) { + var mappedConfigFilename = configFilename; + + if (HostingEnvironment.IsHosted) { + if (!VirtualPathUtility.IsAppRelative(mappedConfigFilename)) { + if (!mappedConfigFilename.StartsWith("/")) { + mappedConfigFilename = "~/" + mappedConfigFilename; + } + else { + mappedConfigFilename = "~" + mappedConfigFilename; + } + } + + mappedConfigFilename = HostingEnvironment.MapPath(mappedConfigFilename); + } + + OrchardXmlConfigurator.Configure(mappedConfigFilename); + } + } + + /// + /// Configures log4net with a stream containing XML. + /// + /// + public OrchardLog4netFactory(Stream config) { + OrchardXmlConfigurator.Configure(config); + } + + public override Castle.Core.Logging.ILogger Create(string name, LoggerLevel level) { + throw new NotSupportedException("Logger levels cannot be set at runtime. Please review your configuration file."); + } + + public override Castle.Core.Logging.ILogger Create(string name) { + return new OrchardLog4netLogger(LogManager.GetLogger(name), this); + } + } +} diff --git a/src/Orchard/Logging/OrchardLog4netLogger.cs b/src/Orchard/Logging/OrchardLog4netLogger.cs new file mode 100644 index 000000000..8998fd0b1 --- /dev/null +++ b/src/Orchard/Logging/OrchardLog4netLogger.cs @@ -0,0 +1,347 @@ +// Copyright 2004-2010 Castle Project - http://www.castleproject.org/ +// +// 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. + +using System; +using System.Globalization; + +using log4net; +using log4net.Core; +using log4net.Util; + +using Logger = Castle.Core.Logging.ILogger; + +namespace Orchard.Logging { + [Serializable] + public class OrchardLog4netLogger : MarshalByRefObject, Logger { + private static readonly Type declaringType = typeof(OrchardLog4netLogger); + + public OrchardLog4netLogger(log4net.Core.ILogger logger, OrchardLog4netFactory factory) { + Logger = logger; + Factory = factory; + } + + internal OrchardLog4netLogger() { + } + + internal OrchardLog4netLogger(ILog log, OrchardLog4netFactory factory) + : this(log.Logger, factory) { + } + + public bool IsDebugEnabled { + get { return Logger.IsEnabledFor(Level.Debug); } + } + + public bool IsErrorEnabled { + get { return Logger.IsEnabledFor(Level.Error); } + } + + public bool IsFatalEnabled { + get { return Logger.IsEnabledFor(Level.Fatal); } + } + + public bool IsInfoEnabled { + get { return Logger.IsEnabledFor(Level.Info); } + } + + public bool IsWarnEnabled { + get { return Logger.IsEnabledFor(Level.Warn); } + } + + protected internal OrchardLog4netFactory Factory { get; set; } + + protected internal log4net.Core.ILogger Logger { get; set; } + + public override string ToString() { + return Logger.ToString(); + } + + public virtual Logger CreateChildLogger(String name) { + return Factory.Create(Logger.Name + "." + name); + } + + public void Debug(String message) { + if (IsDebugEnabled) { + Logger.Log(declaringType, Level.Debug, message, null); + } + } + + public void Debug(Func messageFactory) { + if (IsDebugEnabled) { + Logger.Log(declaringType, Level.Debug, messageFactory.Invoke(), null); + } + } + + public void Debug(String message, Exception exception) { + if (IsDebugEnabled) { + Logger.Log(declaringType, Level.Debug, message, exception); + } + } + + public void DebugFormat(String format, params Object[] args) { + if (IsDebugEnabled) { + Logger.Log(declaringType, Level.Debug, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); + } + } + + public void DebugFormat(Exception exception, String format, params Object[] args) { + if (IsDebugEnabled) { + Logger.Log(declaringType, Level.Debug, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); + } + } + + public void DebugFormat(IFormatProvider formatProvider, String format, params Object[] args) { + if (IsDebugEnabled) { + Logger.Log(declaringType, Level.Debug, new SystemStringFormat(formatProvider, format, args), null); + } + } + + public void DebugFormat(Exception exception, IFormatProvider formatProvider, String format, params Object[] args) { + if (IsDebugEnabled) { + Logger.Log(declaringType, Level.Debug, new SystemStringFormat(formatProvider, format, args), exception); + } + } + + public void Error(String message) { + if (IsErrorEnabled) { + Logger.Log(declaringType, Level.Error, message, null); + } + } + + public void Error(Func messageFactory) { + if (IsErrorEnabled) { + Logger.Log(declaringType, Level.Error, messageFactory.Invoke(), null); + } + } + + public void Error(String message, Exception exception) { + if (IsErrorEnabled) { + Logger.Log(declaringType, Level.Error, message, exception); + } + } + + public void ErrorFormat(String format, params Object[] args) { + if (IsErrorEnabled) { + Logger.Log(declaringType, Level.Error, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); + } + } + + public void ErrorFormat(Exception exception, String format, params Object[] args) { + if (IsErrorEnabled) { + Logger.Log(declaringType, Level.Error, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); + } + } + + public void ErrorFormat(IFormatProvider formatProvider, String format, params Object[] args) { + if (IsErrorEnabled) { + Logger.Log(declaringType, Level.Error, new SystemStringFormat(formatProvider, format, args), null); + } + } + + public void ErrorFormat(Exception exception, IFormatProvider formatProvider, String format, params Object[] args) { + if (IsErrorEnabled) { + Logger.Log(declaringType, Level.Error, new SystemStringFormat(formatProvider, format, args), exception); + } + } + + public void Fatal(String message) { + if (IsFatalEnabled) { + Logger.Log(declaringType, Level.Fatal, message, null); + } + } + + public void Fatal(Func messageFactory) { + if (IsFatalEnabled) { + Logger.Log(declaringType, Level.Fatal, messageFactory.Invoke(), null); + } + } + + public void Fatal(String message, Exception exception) { + if (IsFatalEnabled) { + Logger.Log(declaringType, Level.Fatal, message, exception); + } + } + + public void FatalFormat(String format, params Object[] args) { + if (IsFatalEnabled) { + Logger.Log(declaringType, Level.Fatal, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); + } + } + + public void FatalFormat(Exception exception, String format, params Object[] args) { + if (IsFatalEnabled) { + Logger.Log(declaringType, Level.Fatal, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); + } + } + + public void FatalFormat(IFormatProvider formatProvider, String format, params Object[] args) { + if (IsFatalEnabled) { + Logger.Log(declaringType, Level.Fatal, new SystemStringFormat(formatProvider, format, args), null); + } + } + + public void FatalFormat(Exception exception, IFormatProvider formatProvider, String format, params Object[] args) { + if (IsFatalEnabled) { + Logger.Log(declaringType, Level.Fatal, new SystemStringFormat(formatProvider, format, args), exception); + } + } + + public void Info(String message) { + if (IsInfoEnabled) { + Logger.Log(declaringType, Level.Info, message, null); + } + } + + public void Info(Func messageFactory) { + if (IsInfoEnabled) { + Logger.Log(declaringType, Level.Info, messageFactory.Invoke(), null); + } + } + + public void Info(String message, Exception exception) { + if (IsInfoEnabled) { + Logger.Log(declaringType, Level.Info, message, exception); + } + } + + public void InfoFormat(String format, params Object[] args) { + if (IsInfoEnabled) { + Logger.Log(declaringType, Level.Info, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); + } + } + + public void InfoFormat(Exception exception, String format, params Object[] args) { + if (IsInfoEnabled) { + Logger.Log(declaringType, Level.Info, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); + } + } + + public void InfoFormat(IFormatProvider formatProvider, String format, params Object[] args) { + if (IsInfoEnabled) { + Logger.Log(declaringType, Level.Info, new SystemStringFormat(formatProvider, format, args), null); + } + } + + public void InfoFormat(Exception exception, IFormatProvider formatProvider, String format, params Object[] args) { + if (IsInfoEnabled) { + Logger.Log(declaringType, Level.Info, new SystemStringFormat(formatProvider, format, args), exception); + } + } + + public void Warn(String message) { + if (IsWarnEnabled) { + Logger.Log(declaringType, Level.Warn, message, null); + } + } + + public void Warn(Func messageFactory) { + if (IsWarnEnabled) { + Logger.Log(declaringType, Level.Warn, messageFactory.Invoke(), null); + } + } + + public void Warn(String message, Exception exception) { + if (IsWarnEnabled) { + Logger.Log(declaringType, Level.Warn, message, exception); + } + } + + public void WarnFormat(String format, params Object[] args) { + if (IsWarnEnabled) { + Logger.Log(declaringType, Level.Warn, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); + } + } + + public void WarnFormat(Exception exception, String format, params Object[] args) { + if (IsWarnEnabled) { + Logger.Log(declaringType, Level.Warn, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); + } + } + + public void WarnFormat(IFormatProvider formatProvider, String format, params Object[] args) { + if (IsWarnEnabled) { + Logger.Log(declaringType, Level.Warn, new SystemStringFormat(formatProvider, format, args), null); + } + } + + public void WarnFormat(Exception exception, IFormatProvider formatProvider, String format, params Object[] args) { + if (IsWarnEnabled) { + Logger.Log(declaringType, Level.Warn, new SystemStringFormat(formatProvider, format, args), exception); + } + } + + [Obsolete("Use IsFatalEnabled instead")] + public bool IsFatalErrorEnabled { + get { + return Logger.IsEnabledFor(Level.Fatal); + } + } + + [Obsolete("Use DebugFormat instead")] + public void Debug(string format, params object[] args) { + if (IsDebugEnabled) { + Logger.Log(declaringType, Level.Debug, string.Format(format, args), null); + } + } + + [Obsolete("Use ErrorFormat instead")] + public void Error(string format, params object[] args) { + if (IsErrorEnabled) { + Logger.Log(declaringType, Level.Error, string.Format(format, args), null); + } + } + + [Obsolete("Use FatalFormat instead")] + public void Fatal(string format, params object[] args) { + if (IsFatalEnabled) { + Logger.Log(declaringType, Level.Fatal, string.Format(format, args), null); + } + } + + [Obsolete("Use Fatal instead")] + public void FatalError(string message) { + if (IsFatalErrorEnabled) { + Logger.Log(declaringType, Level.Fatal, message, null); + } + } + + [Obsolete("Use FatalFormat instead")] + public void FatalError(string format, params object[] args) { + if (IsFatalErrorEnabled) { + Logger.Log(declaringType, Level.Fatal, string.Format(format, args), null); + } + } + + [Obsolete("Use Fatal instead")] + public void FatalError(string message, Exception exception) { + if (IsFatalErrorEnabled) { + Logger.Log(declaringType, Level.Fatal, message, exception); + } + } + + [Obsolete("Use InfoFormat instead")] + public void Info(string format, params object[] args) { + if (IsInfoEnabled) { + Logger.Log(declaringType, Level.Info, string.Format(format, args), null); + } + } + + [Obsolete("Use WarnFormat instead")] + public void Warn(string format, params object[] args) { + if (IsWarnEnabled) { + Logger.Log(declaringType, Level.Warn, string.Format(format, args), null); + } + } + + } +} \ No newline at end of file diff --git a/src/Orchard/Logging/OrchardXmlConfigurator.cs b/src/Orchard/Logging/OrchardXmlConfigurator.cs new file mode 100644 index 000000000..b301301c5 --- /dev/null +++ b/src/Orchard/Logging/OrchardXmlConfigurator.cs @@ -0,0 +1,325 @@ +using System; +using System.Xml; +using System.Collections; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Net; + +using log4net; +using log4net.Appender; +using log4net.Util; +using log4net.Repository; +using log4net.Repository.Hierarchy; + +namespace Orchard.Logging { + public class OrchardXmlConfigurator { + #region Private Instance Constructors + + /// + /// Private constructor + /// + private OrchardXmlConfigurator() { + } + + #endregion Protected Instance Constructors + + #region Configure static methods + + /// + /// Configures log4net using the specified configuration file. + /// + /// The name of the XML file to load the configuration from. + /// + /// + /// The configuration file must be valid XML. It must contain + /// at least one element called log4net that holds + /// the log4net configuration data. + /// + /// + /// The log4net configuration file can possible be specified in the application's + /// configuration file (either MyAppName.exe.config for a + /// normal application on Web.config for an ASP.NET application). + /// + /// + /// The first element matching <configuration> will be read as the + /// configuration. If this file is also a .NET .config file then you must specify + /// a configuration section for the log4net element otherwise .NET will + /// complain. Set the type for the section handler to , for example: + /// + /// + ///
+ /// + /// + /// + /// + /// The following example configures log4net using a configuration file, of which the + /// location is stored in the application's configuration file : + /// + /// + /// using log4net.Config; + /// using System.IO; + /// using System.Configuration; + /// + /// ... + /// + /// XmlConfigurator.Configure(ConfigurationSettings.AppSettings["log4net-config-file"]); + /// + /// + /// In the .config file, the path to the log4net can be specified like this : + /// + /// + /// + /// + /// + /// + /// + /// + /// + static public void Configure(string configFilename) { + Configure(LogManager.GetRepository(Assembly.GetCallingAssembly()), configFilename); + } + + /// + /// Configures log4net using the specified configuration data stream. + /// + /// A stream to load the XML configuration from. + /// + /// + /// The configuration data must be valid XML. It must contain + /// at least one element called log4net that holds + /// the log4net configuration data. + /// + /// + /// Note that this method will NOT close the stream parameter. + /// + /// + static public void Configure(Stream configStream) { + Configure(LogManager.GetRepository(Assembly.GetCallingAssembly()), configStream); + } + + /// + /// Configures the using the specified configuration + /// file. + /// + /// The repository to configure. + /// The name of the XML file to load the configuration from. + /// + /// + /// The configuration file must be valid XML. It must contain + /// at least one element called log4net that holds + /// the configuration data. + /// + /// + /// The log4net configuration file can possible be specified in the application's + /// configuration file (either MyAppName.exe.config for a + /// normal application on Web.config for an ASP.NET application). + /// + /// + /// The first element matching <configuration> will be read as the + /// configuration. If this file is also a .NET .config file then you must specify + /// a configuration section for the log4net element otherwise .NET will + /// complain. Set the type for the section handler to , for example: + /// + /// + ///
+ /// + /// + /// + /// + /// The following example configures log4net using a configuration file, of which the + /// location is stored in the application's configuration file : + /// + /// + /// using log4net.Config; + /// using System.IO; + /// using System.Configuration; + /// + /// ... + /// + /// XmlConfigurator.Configure(ConfigurationSettings.AppSettings["log4net-config-file"]); + /// + /// + /// In the .config file, the path to the log4net can be specified like this : + /// + /// + /// + /// + /// + /// + /// + /// + /// + static public void Configure(ILoggerRepository repository, string configFilename) { + LogLog.Debug("XmlConfigurator: configuring repository [" + repository.Name + "] using file [" + configFilename + "]"); + + if (String.IsNullOrWhiteSpace(configFilename)) { + LogLog.Error("XmlConfigurator: Configure called with null 'configFilename' parameter"); + } + else { + // Have to use File.Exists() rather than configFile.Exists() + // because configFile.Exists() caches the value, not what we want. + if (File.Exists(configFilename)) { + // Open the file for reading + FileStream fs = null; + + // Try hard to open the file + for (int retry = 5; --retry >= 0; ) { + try { + fs = new FileStream(configFilename, FileMode.Open, FileAccess.Read, FileShare.Read); + break; + } + catch (IOException ex) { + if (retry == 0) { + LogLog.Error("XmlConfigurator: Failed to open XML config file [" + configFilename + "]", ex); + + // The stream cannot be valid + fs = null; + } + + System.Threading.Thread.Sleep(250); + } + } + + if (fs != null) { + try { + // Load the configuration from the stream + Configure(repository, fs); + } + finally { + // Force the file closed whatever happens + fs.Close(); + } + } + } + else { + LogLog.Debug("XmlConfigurator: config file [" + configFilename + "] not found. Configuration unchanged."); + } + } + } + + /// + /// Configures the using the specified configuration + /// file. + /// + /// The repository to configure. + /// The stream to load the XML configuration from. + /// + /// + /// The configuration data must be valid XML. It must contain + /// at least one element called log4net that holds + /// the configuration data. + /// + /// + /// Note that this method will NOT close the stream parameter. + /// + /// + static public void Configure(ILoggerRepository repository, Stream configStream) { + LogLog.Debug("XmlConfigurator: configuring repository [" + repository.Name + "] using stream"); + + if (configStream == null) { + LogLog.Error("XmlConfigurator: Configure called with null 'configStream' parameter"); + } + else { + // Load the config file into a document + XmlDocument doc = new XmlDocument(); + try { + // Create a text reader for the file stream + XmlTextReader xmlReader = new XmlTextReader(configStream); + xmlReader.DtdProcessing = DtdProcessing.Parse; + + // Specify that the reader should not perform validation + XmlReaderSettings settings = new XmlReaderSettings(); + settings.ValidationType = ValidationType.None; + + // load the data into the document + doc.Load(xmlReader); + } + catch (Exception ex) { + LogLog.Error("XmlConfigurator: Error while loading XML configuration", ex); + + // The document is invalid + doc = null; + } + + if (doc != null) { + LogLog.Debug("XmlConfigurator: loading XML configuration"); + + // Configure using the 'log4net' element + XmlNodeList configNodeList = doc.GetElementsByTagName("log4net"); + if (configNodeList.Count == 0) { + LogLog.Debug("XmlConfigurator: XML configuration does not contain a element. Configuration Aborted."); + } + else if (configNodeList.Count > 1) { + LogLog.Error("XmlConfigurator: XML configuration contains [" + configNodeList.Count + "] elements. Only one is allowed. Configuration Aborted."); + } + else { + ConfigureFromXml(repository, configNodeList[0] as XmlElement); + } + } + } + } + + #endregion Configure static methods + + #region Private Static Methods + + /// + /// Configures the specified repository using a log4net element. + /// + /// The hierarchy to configure. + /// The element to parse. + /// + /// + /// Loads the log4net configuration from the XML element + /// supplied as . + /// + /// + /// This method is ultimately called by one of the Configure methods + /// to load the configuration from an . + /// + /// + static private void ConfigureFromXml(ILoggerRepository repository, XmlElement element) { + if (element == null) { + LogLog.Error("XmlConfigurator: ConfigureFromXml called with null 'element' parameter"); + } + else if (repository == null) { + LogLog.Error("XmlConfigurator: ConfigureFromXml called with null 'repository' parameter"); + } + else { + LogLog.Debug("XmlConfigurator: Configuring Repository [" + repository.Name + "]"); + + // + // Since we're not reinventing the whole Hierarchy class from log4net to add out optimizations to XmlRepositoryConfigurator + // we've to check the neccessary casts here to be able to complete the configuration. + // + + // Needed to fire configuration changed event + LoggerRepositorySkeleton repositorySkeleton = repository as LoggerRepositorySkeleton; + + // Needed to XmlHierarchyConfigurator + Hierarchy hierarchy = repository as Hierarchy; + + if (repositorySkeleton == null || hierarchy == null) { + LogLog.Warn("XmlConfigurator: Repository [" + repository + "] does not support the XmlConfigurator"); + } + else { + OrchardXmlHierarchyConfigurator configurator = new OrchardXmlHierarchyConfigurator(hierarchy); + + // Copy the xml data into the root of a new document + // this isolates the xml config data from the rest of + // the document + XmlDocument newDoc = new XmlDocument(); + XmlElement newElement = (XmlElement)newDoc.AppendChild(newDoc.ImportNode(element, true)); + + // Pass the configurator the config element + configurator.Configure(newElement); + + repositorySkeleton.RaiseConfigurationChanged(EventArgs.Empty); + } + } + } + + #endregion Private Static Methods + } +} diff --git a/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs b/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs new file mode 100644 index 000000000..156e277e7 --- /dev/null +++ b/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs @@ -0,0 +1,902 @@ +using System; +using System.Collections; +using System.Globalization; +using System.Reflection; +using System.Xml; + +using log4net.Appender; +using log4net.Util; +using log4net.Core; +using log4net.ObjectRenderer; +using log4net.Repository.Hierarchy; + +namespace Orchard.Logging { + /// + /// Initializes the log4net environment using an XML DOM. + /// + /// + /// + /// Configures a using an XML DOM. + /// + /// + /// Nicko Cadell + /// Gert Driesen + public class OrchardXmlHierarchyConfigurator { + private enum ConfigUpdateMode { + Merge, + Overwrite + } + + #region Public Instance Constructors + + /// + /// Construct the configurator for a hierarchy + /// + /// The hierarchy to build. + /// + /// + /// Initializes a new instance of the class + /// with the specified . + /// + /// + public OrchardXmlHierarchyConfigurator(Hierarchy hierarchy) { + m_hierarchy = hierarchy; + m_appenderBag = new Hashtable(); + } + + #endregion Public Instance Constructors + + #region Public Instance Methods + + /// + /// Configure the hierarchy by parsing a DOM tree of XML elements. + /// + /// The root element to parse. + /// + /// + /// Configure the hierarchy by parsing a DOM tree of XML elements. + /// + /// + public void Configure(XmlElement element) { + if (element == null || m_hierarchy == null) { + return; + } + + string rootElementName = element.LocalName; + + if (rootElementName != CONFIGURATION_TAG) { + LogLog.Error("XmlHierarchyConfigurator: Xml element is - not a <" + CONFIGURATION_TAG + "> element."); + return; + } + + if (!LogLog.InternalDebugging) { + // Look for a debug attribute to enable internal debug + string debugAttribute = element.GetAttribute(INTERNAL_DEBUG_ATTR); + LogLog.Debug("XmlHierarchyConfigurator: " + INTERNAL_DEBUG_ATTR + " attribute [" + debugAttribute + "]."); + + if (debugAttribute.Length > 0 && debugAttribute != "null") { + LogLog.InternalDebugging = OptionConverter.ToBoolean(debugAttribute, true); + } + else { + LogLog.Debug("XmlHierarchyConfigurator: Ignoring " + INTERNAL_DEBUG_ATTR + " attribute."); + } + + string confDebug = element.GetAttribute(CONFIG_DEBUG_ATTR); + if (confDebug.Length > 0 && confDebug != "null") { + LogLog.Warn("XmlHierarchyConfigurator: The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated."); + LogLog.Warn("XmlHierarchyConfigurator: Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead."); + LogLog.InternalDebugging = OptionConverter.ToBoolean(confDebug, true); + } + } + + // Default mode is merge + ConfigUpdateMode configUpdateMode = ConfigUpdateMode.Merge; + + // Look for the config update attribute + string configUpdateModeAttribute = element.GetAttribute(CONFIG_UPDATE_MODE_ATTR); + if (configUpdateModeAttribute != null && configUpdateModeAttribute.Length > 0) { + // Parse the attribute + try { + configUpdateMode = (ConfigUpdateMode)OptionConverter.ConvertStringTo(typeof(ConfigUpdateMode), configUpdateModeAttribute); + } + catch { + LogLog.Error("XmlHierarchyConfigurator: Invalid " + CONFIG_UPDATE_MODE_ATTR + " attribute value [" + configUpdateModeAttribute + "]"); + } + } + + // IMPL: The IFormatProvider argument to Enum.ToString() is deprecated in .NET 2.0 + LogLog.Debug("XmlHierarchyConfigurator: Configuration update mode [" + configUpdateMode.ToString() + "]."); + + // Only reset configuration if overwrite flag specified + if (configUpdateMode == ConfigUpdateMode.Overwrite) { + // Reset to original unset configuration + m_hierarchy.ResetConfiguration(); + LogLog.Debug("XmlHierarchyConfigurator: Configuration reset before reading config."); + } + + // Try to retrieve the environment variables + try { + m_environmentVariables = System.Environment.GetEnvironmentVariables(); + } + catch (System.Security.SecurityException) { + m_environmentVariables = null; + + // This security exception will occur if the caller does not have + // unrestricted environment permission. If this occurs the expansion + // will be skipped with the following warning message. + LogLog.Debug("XmlHierarchyConfigurator: Security exception while trying to expand environment variables. Error Ignored. No Expansion."); + } + + /* Building Appender objects, placing them in a local namespace + for future reference */ + + /* Process all the top level elements */ + + foreach (XmlNode currentNode in element.ChildNodes) { + if (currentNode.NodeType == XmlNodeType.Element) { + XmlElement currentElement = (XmlElement)currentNode; + + if (currentElement.LocalName == LOGGER_TAG) { + ParseLogger(currentElement); + } + else if (currentElement.LocalName == CATEGORY_TAG) { + // TODO: deprecated use of category + ParseLogger(currentElement); + } + else if (currentElement.LocalName == ROOT_TAG) { + ParseRoot(currentElement); + } + else if (currentElement.LocalName == RENDERER_TAG) { + ParseRenderer(currentElement); + } + else if (currentElement.LocalName == APPENDER_TAG) { + // We ignore appenders in this pass. They will + // be found and loaded if they are referenced. + } + else { + // Read the param tags and set properties on the hierarchy + SetParameter(currentElement, m_hierarchy); + } + } + } + + // Lastly set the hierarchy threshold + string thresholdStr = element.GetAttribute(THRESHOLD_ATTR); + LogLog.Debug("XmlHierarchyConfigurator: Hierarchy Threshold [" + thresholdStr + "]"); + if (thresholdStr.Length > 0 && thresholdStr != "null") { + Level thresholdLevel = (Level)ConvertStringTo(typeof(Level), thresholdStr); + if (thresholdLevel != null) { + m_hierarchy.Threshold = thresholdLevel; + } + else { + LogLog.Warn("XmlHierarchyConfigurator: Unable to set hierarchy threshold using value [" + thresholdStr + "] (with acceptable conversion types)"); + } + } + + // Done reading config + } + + #endregion Public Instance Methods + + #region Protected Instance Methods + + /// + /// Parse appenders by IDREF. + /// + /// The appender ref element. + /// The instance of the appender that the ref refers to. + /// + /// + /// Parse an XML element that represents an appender and return + /// the appender. + /// + /// + protected IAppender FindAppenderByReference(XmlElement appenderRef) { + string appenderName = appenderRef.GetAttribute(REF_ATTR); + + IAppender appender = (IAppender)m_appenderBag[appenderName]; + if (appender != null) { + return appender; + } + else { + // Find the element with that id + XmlElement element = null; + + if (appenderName != null && appenderName.Length > 0) { + foreach (XmlElement curAppenderElement in appenderRef.OwnerDocument.GetElementsByTagName(APPENDER_TAG)) { + if (curAppenderElement.GetAttribute("name") == appenderName) { + element = curAppenderElement; + break; + } + } + } + + if (element == null) { + LogLog.Error("XmlHierarchyConfigurator: No appender named [" + appenderName + "] could be found."); + return null; + } + else { + appender = ParseAppender(element); + if (appender != null) { + m_appenderBag[appenderName] = appender; + } + return appender; + } + } + } + + /// + /// Parses an appender element. + /// + /// The appender element. + /// The appender instance or null when parsing failed. + /// + /// + /// Parse an XML element that represents an appender and return + /// the appender instance. + /// + /// + protected IAppender ParseAppender(XmlElement appenderElement) { + string appenderName = appenderElement.GetAttribute(NAME_ATTR); + string typeName = appenderElement.GetAttribute(TYPE_ATTR); + + LogLog.Debug("XmlHierarchyConfigurator: Loading Appender [" + appenderName + "] type: [" + typeName + "]"); + try { + IAppender appender = (IAppender)Activator.CreateInstance(SystemInfo.GetTypeFromString(typeName, true, true)); + appender.Name = appenderName; + + foreach (XmlNode currentNode in appenderElement.ChildNodes) { + /* We're only interested in Elements */ + if (currentNode.NodeType == XmlNodeType.Element) { + XmlElement currentElement = (XmlElement)currentNode; + + // Look for the appender ref tag + if (currentElement.LocalName == APPENDER_REF_TAG) { + string refName = currentElement.GetAttribute(REF_ATTR); + + IAppenderAttachable appenderContainer = appender as IAppenderAttachable; + if (appenderContainer != null) { + LogLog.Debug("XmlHierarchyConfigurator: Attaching appender named [" + refName + "] to appender named [" + appender.Name + "]."); + + IAppender referencedAppender = FindAppenderByReference(currentElement); + if (referencedAppender != null) { + appenderContainer.AddAppender(referencedAppender); + } + } + else { + LogLog.Error("XmlHierarchyConfigurator: Requesting attachment of appender named [" + refName + "] to appender named [" + appender.Name + "] which does not implement log4net.Core.IAppenderAttachable."); + } + } + else { + // For all other tags we use standard set param method + SetParameter(currentElement, appender); + } + } + } + + IOptionHandler optionHandler = appender as IOptionHandler; + if (optionHandler != null) { + optionHandler.ActivateOptions(); + } + + LogLog.Debug("XmlHierarchyConfigurator: Created Appender [" + appenderName + "]"); + return appender; + } + catch (Exception ex) { + // Yes, it's ugly. But all exceptions point to the same problem: we can't create an Appender + + LogLog.Error("XmlHierarchyConfigurator: Could not create Appender [" + appenderName + "] of type [" + typeName + "]. Reported error follows.", ex); + return null; + } + } + + /// + /// Parses a logger element. + /// + /// The logger element. + /// + /// + /// Parse an XML element that represents a logger. + /// + /// + protected void ParseLogger(XmlElement loggerElement) { + // Create a new log4net.Logger object from the element. + string loggerName = loggerElement.GetAttribute(NAME_ATTR); + + LogLog.Debug("XmlHierarchyConfigurator: Retrieving an instance of log4net.Repository.Logger for logger [" + loggerName + "]."); + Logger log = m_hierarchy.GetLogger(loggerName) as Logger; + + // Setting up a logger needs to be an atomic operation, in order + // to protect potential log operations while logger + // configuration is in progress. + lock (log) { + bool additivity = OptionConverter.ToBoolean(loggerElement.GetAttribute(ADDITIVITY_ATTR), true); + + LogLog.Debug("XmlHierarchyConfigurator: Setting [" + log.Name + "] additivity to [" + additivity + "]."); + log.Additivity = additivity; + ParseChildrenOfLoggerElement(loggerElement, log, false); + } + } + + /// + /// Parses the root logger element. + /// + /// The root element. + /// + /// + /// Parse an XML element that represents the root logger. + /// + /// + protected void ParseRoot(XmlElement rootElement) { + Logger root = m_hierarchy.Root; + // logger configuration needs to be atomic + lock (root) { + ParseChildrenOfLoggerElement(rootElement, root, true); + } + } + + /// + /// Parses the children of a logger element. + /// + /// The category element. + /// The logger instance. + /// Flag to indicate if the logger is the root logger. + /// + /// + /// Parse the child elements of a <logger> element. + /// + /// + protected void ParseChildrenOfLoggerElement(XmlElement catElement, Logger log, bool isRoot) { + // Remove all existing appenders from log. They will be + // reconstructed if need be. + log.RemoveAllAppenders(); + + foreach (XmlNode currentNode in catElement.ChildNodes) { + if (currentNode.NodeType == XmlNodeType.Element) { + XmlElement currentElement = (XmlElement)currentNode; + + if (currentElement.LocalName == APPENDER_REF_TAG) { + IAppender appender = FindAppenderByReference(currentElement); + string refName = currentElement.GetAttribute(REF_ATTR); + if (appender != null) { + LogLog.Debug("XmlHierarchyConfigurator: Adding appender named [" + refName + "] to logger [" + log.Name + "]."); + log.AddAppender(appender); + } + else { + LogLog.Error("XmlHierarchyConfigurator: Appender named [" + refName + "] not found."); + } + } + else if (currentElement.LocalName == LEVEL_TAG || currentElement.LocalName == PRIORITY_TAG) { + ParseLevel(currentElement, log, isRoot); + } + else { + SetParameter(currentElement, log); + } + } + } + + IOptionHandler optionHandler = log as IOptionHandler; + if (optionHandler != null) { + optionHandler.ActivateOptions(); + } + } + + /// + /// Parses an object renderer. + /// + /// The renderer element. + /// + /// + /// Parse an XML element that represents a renderer. + /// + /// + protected void ParseRenderer(XmlElement element) { + string renderingClassName = element.GetAttribute(RENDERING_TYPE_ATTR); + string renderedClassName = element.GetAttribute(RENDERED_TYPE_ATTR); + + LogLog.Debug("XmlHierarchyConfigurator: Rendering class [" + renderingClassName + "], Rendered class [" + renderedClassName + "]."); + IObjectRenderer renderer = (IObjectRenderer)OptionConverter.InstantiateByClassName(renderingClassName, typeof(IObjectRenderer), null); + if (renderer == null) { + LogLog.Error("XmlHierarchyConfigurator: Could not instantiate renderer [" + renderingClassName + "]."); + return; + } + else { + try { + m_hierarchy.RendererMap.Put(SystemInfo.GetTypeFromString(renderedClassName, true, true), renderer); + } + catch (Exception e) { + LogLog.Error("XmlHierarchyConfigurator: Could not find class [" + renderedClassName + "].", e); + } + } + } + + /// + /// Parses a level element. + /// + /// The level element. + /// The logger object to set the level on. + /// Flag to indicate if the logger is the root logger. + /// + /// + /// Parse an XML element that represents a level. + /// + /// + protected void ParseLevel(XmlElement element, Logger log, bool isRoot) { + string loggerName = log.Name; + if (isRoot) { + loggerName = "root"; + } + + string levelStr = element.GetAttribute(VALUE_ATTR); + LogLog.Debug("XmlHierarchyConfigurator: Logger [" + loggerName + "] Level string is [" + levelStr + "]."); + + if (INHERITED == levelStr) { + if (isRoot) { + LogLog.Error("XmlHierarchyConfigurator: Root level cannot be inherited. Ignoring directive."); + } + else { + LogLog.Debug("XmlHierarchyConfigurator: Logger [" + loggerName + "] level set to inherit from parent."); + log.Level = null; + } + } + else { + log.Level = log.Hierarchy.LevelMap[levelStr]; + if (log.Level == null) { + LogLog.Error("XmlHierarchyConfigurator: Undefined level [" + levelStr + "] on Logger [" + loggerName + "]."); + } + else { + LogLog.Debug("XmlHierarchyConfigurator: Logger [" + loggerName + "] level set to [name=\"" + log.Level.Name + "\",value=" + log.Level.Value + "]."); + } + } + } + + /// + /// Sets a parameter on an object. + /// + /// The parameter element. + /// The object to set the parameter on. + /// + /// The parameter name must correspond to a writable property + /// on the object. The value of the parameter is a string, + /// therefore this function will attempt to set a string + /// property first. If unable to set a string property it + /// will inspect the property and its argument type. It will + /// attempt to call a static method called Parse on the + /// type of the property. This method will take a single + /// string argument and return a value that can be used to + /// set the property. + /// + protected void SetParameter(XmlElement element, object target) { + // Get the property name + string name = element.GetAttribute(NAME_ATTR); + + // If the name attribute does not exist then use the name of the element + if (element.LocalName != PARAM_TAG || name == null || name.Length == 0) { + name = element.LocalName; + } + + // Look for the property on the target object + Type targetType = target.GetType(); + Type propertyType = null; + + PropertyInfo propInfo = null; + MethodInfo methInfo = null; + + // Try to find a writable property + propInfo = targetType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase); + if (propInfo != null && propInfo.CanWrite) { + // found a property + propertyType = propInfo.PropertyType; + } + else { + propInfo = null; + + // look for a method with the signature Add(type) + methInfo = FindMethodInfo(targetType, name); + + if (methInfo != null) { + propertyType = methInfo.GetParameters()[0].ParameterType; + } + } + + if (propertyType == null) { + LogLog.Error("XmlHierarchyConfigurator: Cannot find Property [" + name + "] to set object on [" + target.ToString() + "]"); + } + else { + string propertyValue = null; + + if (element.GetAttributeNode(VALUE_ATTR) != null) { + propertyValue = element.GetAttribute(VALUE_ATTR); + } + else if (element.HasChildNodes) { + // Concatenate the CDATA and Text nodes together + foreach (XmlNode childNode in element.ChildNodes) { + if (childNode.NodeType == XmlNodeType.CDATA || childNode.NodeType == XmlNodeType.Text) { + if (propertyValue == null) { + propertyValue = childNode.InnerText; + } + else { + propertyValue += childNode.InnerText; + } + } + } + } + + if (propertyValue != null) { + if (m_environmentVariables != null) { + // Expand environment variables in the string. + propertyValue = OptionConverter.SubstituteVariables(propertyValue, m_environmentVariables); + } + + Type parsedObjectConversionTargetType = null; + + // Check if a specific subtype is specified on the element using the 'type' attribute + string subTypeString = element.GetAttribute(TYPE_ATTR); + if (subTypeString != null && subTypeString.Length > 0) { + // Read the explicit subtype + try { + Type subType = SystemInfo.GetTypeFromString(subTypeString, true, true); + + LogLog.Debug("XmlHierarchyConfigurator: Parameter [" + name + "] specified subtype [" + subType.FullName + "]"); + + if (!propertyType.IsAssignableFrom(subType)) { + // Check if there is an appropriate type converter + if (OptionConverter.CanConvertTypeTo(subType, propertyType)) { + // Must re-convert to the real property type + parsedObjectConversionTargetType = propertyType; + + // Use sub type as intermediary type + propertyType = subType; + } + else { + LogLog.Error("XmlHierarchyConfigurator: Subtype [" + subType.FullName + "] set on [" + name + "] is not a subclass of property type [" + propertyType.FullName + "] and there are no acceptable type conversions."); + } + } + else { + // The subtype specified is found and is actually a subtype of the property + // type, therefore we can switch to using this type. + propertyType = subType; + } + } + catch (Exception ex) { + LogLog.Error("XmlHierarchyConfigurator: Failed to find type [" + subTypeString + "] set on [" + name + "]", ex); + } + } + + // Now try to convert the string value to an acceptable type + // to pass to this property. + + object convertedValue = ConvertStringTo(propertyType, propertyValue); + + // Check if we need to do an additional conversion + if (convertedValue != null && parsedObjectConversionTargetType != null) { + LogLog.Debug("XmlHierarchyConfigurator: Performing additional conversion of value from [" + convertedValue.GetType().Name + "] to [" + parsedObjectConversionTargetType.Name + "]"); + convertedValue = OptionConverter.ConvertTypeTo(convertedValue, parsedObjectConversionTargetType); + } + + if (convertedValue != null) { + if (propInfo != null) { + // Got a converted result + LogLog.Debug("XmlHierarchyConfigurator: Setting Property [" + propInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue.ToString() + "]"); + + try { + // Pass to the property + propInfo.SetValue(target, convertedValue, BindingFlags.SetProperty, null, null, CultureInfo.InvariantCulture); + } + catch (TargetInvocationException targetInvocationEx) { + LogLog.Error("XmlHierarchyConfigurator: Failed to set parameter [" + propInfo.Name + "] on object [" + target + "] using value [" + convertedValue + "]", targetInvocationEx.InnerException); + } + } + else if (methInfo != null) { + // Got a converted result + LogLog.Debug("XmlHierarchyConfigurator: Setting Collection Property [" + methInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue.ToString() + "]"); + + try { + // Pass to the property + methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new object[] { convertedValue }, CultureInfo.InvariantCulture); + } + catch (TargetInvocationException targetInvocationEx) { + LogLog.Error("XmlHierarchyConfigurator: Failed to set parameter [" + name + "] on object [" + target + "] using value [" + convertedValue + "]", targetInvocationEx.InnerException); + } + } + } + else { + LogLog.Warn("XmlHierarchyConfigurator: Unable to set property [" + name + "] on object [" + target + "] using value [" + propertyValue + "] (with acceptable conversion types)"); + } + } + else { + object createdObject = null; + + if (propertyType == typeof(string) && !HasAttributesOrElements(element)) { + // If the property is a string and the element is empty (no attributes + // or child elements) then we special case the object value to an empty string. + // This is necessary because while the String is a class it does not have + // a default constructor that creates an empty string, which is the behavior + // we are trying to simulate and would be expected from CreateObjectFromXml + createdObject = ""; + } + else { + // No value specified + Type defaultObjectType = null; + if (IsTypeConstructible(propertyType)) { + defaultObjectType = propertyType; + } + + createdObject = CreateObjectFromXml(element, defaultObjectType, propertyType); + } + + if (createdObject == null) { + LogLog.Error("XmlHierarchyConfigurator: Failed to create object to set param: " + name); + } + else { + if (propInfo != null) { + // Got a converted result + LogLog.Debug("XmlHierarchyConfigurator: Setting Property [" + propInfo.Name + "] to object [" + createdObject + "]"); + + try { + // Pass to the property + propInfo.SetValue(target, createdObject, BindingFlags.SetProperty, null, null, CultureInfo.InvariantCulture); + } + catch (TargetInvocationException targetInvocationEx) { + LogLog.Error("XmlHierarchyConfigurator: Failed to set parameter [" + propInfo.Name + "] on object [" + target + "] using value [" + createdObject + "]", targetInvocationEx.InnerException); + } + } + else if (methInfo != null) { + // Got a converted result + LogLog.Debug("XmlHierarchyConfigurator: Setting Collection Property [" + methInfo.Name + "] to object [" + createdObject + "]"); + + try { + // Pass to the property + methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new object[] { createdObject }, CultureInfo.InvariantCulture); + } + catch (TargetInvocationException targetInvocationEx) { + LogLog.Error("XmlHierarchyConfigurator: Failed to set parameter [" + methInfo.Name + "] on object [" + target + "] using value [" + createdObject + "]", targetInvocationEx.InnerException); + } + } + } + } + } + } + + /// + /// Test if an element has no attributes or child elements + /// + /// the element to inspect + /// true if the element has any attributes or child elements, false otherwise + private bool HasAttributesOrElements(XmlElement element) { + foreach (XmlNode node in element.ChildNodes) { + if (node.NodeType == XmlNodeType.Attribute || node.NodeType == XmlNodeType.Element) { + return true; + } + } + return false; + } + + /// + /// Test if a is constructible with Activator.CreateInstance. + /// + /// the type to inspect + /// true if the type is creatable using a default constructor, false otherwise + private static bool IsTypeConstructible(Type type) { + if (type.IsClass && !type.IsAbstract) { + ConstructorInfo defaultConstructor = type.GetConstructor(new Type[0]); + if (defaultConstructor != null && !defaultConstructor.IsAbstract && !defaultConstructor.IsPrivate) { + return true; + } + } + return false; + } + + /// + /// Look for a method on the that matches the supplied + /// + /// the type that has the method + /// the name of the method + /// the method info found + /// + /// + /// The method must be a public instance method on the . + /// The method must be named or "Add" followed by . + /// The method must take a single parameter. + /// + /// + private MethodInfo FindMethodInfo(Type targetType, string name) { + string requiredMethodNameA = name; + string requiredMethodNameB = "Add" + name; + + MethodInfo[] methods = targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + + foreach (MethodInfo methInfo in methods) { + if (!methInfo.IsStatic) { + if (string.Compare(methInfo.Name, requiredMethodNameA, true, System.Globalization.CultureInfo.InvariantCulture) == 0 || + string.Compare(methInfo.Name, requiredMethodNameB, true, System.Globalization.CultureInfo.InvariantCulture) == 0) { + // Found matching method name + + // Look for version with one arg only + System.Reflection.ParameterInfo[] methParams = methInfo.GetParameters(); + if (methParams.Length == 1) { + return methInfo; + } + } + } + } + return null; + } + + /// + /// Converts a string value to a target type. + /// + /// The type of object to convert the string to. + /// The string value to use as the value of the object. + /// + /// + /// An object of type with value or + /// null when the conversion could not be performed. + /// + /// + protected object ConvertStringTo(Type type, string value) { + // Hack to allow use of Level in property + if (typeof(Level) == type) { + // Property wants a level + Level levelValue = m_hierarchy.LevelMap[value]; + + if (levelValue == null) { + LogLog.Error("XmlHierarchyConfigurator: Unknown Level Specified [" + value + "]"); + } + + return levelValue; + } + return OptionConverter.ConvertStringTo(type, value); + } + + /// + /// Creates an object as specified in XML. + /// + /// The XML element that contains the definition of the object. + /// The object type to use if not explicitly specified. + /// The type that the returned object must be or must inherit from. + /// The object or null + /// + /// + /// Parse an XML element and create an object instance based on the configuration + /// data. + /// + /// + /// The type of the instance may be specified in the XML. If not + /// specified then the is used + /// as the type. However the type is specified it must support the + /// type. + /// + /// + protected object CreateObjectFromXml(XmlElement element, Type defaultTargetType, Type typeConstraint) { + Type objectType = null; + + // Get the object type + string objectTypeString = element.GetAttribute(TYPE_ATTR); + if (objectTypeString == null || objectTypeString.Length == 0) { + if (defaultTargetType == null) { + LogLog.Error("XmlHierarchyConfigurator: Object type not specified. Cannot create object of type [" + typeConstraint.FullName + "]. Missing Value or Type."); + return null; + } + else { + // Use the default object type + objectType = defaultTargetType; + } + } + else { + // Read the explicit object type + try { + objectType = SystemInfo.GetTypeFromString(objectTypeString, true, true); + } + catch (Exception ex) { + LogLog.Error("XmlHierarchyConfigurator: Failed to find type [" + objectTypeString + "]", ex); + return null; + } + } + + bool requiresConversion = false; + + // Got the object type. Check that it meets the typeConstraint + if (typeConstraint != null) { + if (!typeConstraint.IsAssignableFrom(objectType)) { + // Check if there is an appropriate type converter + if (OptionConverter.CanConvertTypeTo(objectType, typeConstraint)) { + requiresConversion = true; + } + else { + LogLog.Error("XmlHierarchyConfigurator: Object type [" + objectType.FullName + "] is not assignable to type [" + typeConstraint.FullName + "]. There are no acceptable type conversions."); + return null; + } + } + } + + // Create using the default constructor + object createdObject = null; + try { + createdObject = Activator.CreateInstance(objectType); + } + catch (Exception createInstanceEx) { + LogLog.Error("XmlHierarchyConfigurator: Failed to construct object of type [" + objectType.FullName + "] Exception: " + createInstanceEx.ToString()); + } + + // Set any params on object + foreach (XmlNode currentNode in element.ChildNodes) { + if (currentNode.NodeType == XmlNodeType.Element) { + SetParameter((XmlElement)currentNode, createdObject); + } + } + + // Check if we need to call ActivateOptions + IOptionHandler optionHandler = createdObject as IOptionHandler; + if (optionHandler != null) { + optionHandler.ActivateOptions(); + } + + // Ok object should be initialized + + if (requiresConversion) { + // Convert the object type + return OptionConverter.ConvertTypeTo(createdObject, typeConstraint); + } + else { + // The object is of the correct type + return createdObject; + } + } + + #endregion Protected Instance Methods + + #region Private Constants + + // String constants used while parsing the XML data + private const string CONFIGURATION_TAG = "log4net"; + private const string RENDERER_TAG = "renderer"; + private const string APPENDER_TAG = "appender"; + private const string APPENDER_REF_TAG = "appender-ref"; + private const string PARAM_TAG = "param"; + + // TODO: Deprecate use of category tags + private const string CATEGORY_TAG = "category"; + // TODO: Deprecate use of priority tag + private const string PRIORITY_TAG = "priority"; + + private const string LOGGER_TAG = "logger"; + private const string NAME_ATTR = "name"; + private const string TYPE_ATTR = "type"; + private const string VALUE_ATTR = "value"; + private const string ROOT_TAG = "root"; + private const string LEVEL_TAG = "level"; + private const string REF_ATTR = "ref"; + private const string ADDITIVITY_ATTR = "additivity"; + private const string THRESHOLD_ATTR = "threshold"; + private const string CONFIG_DEBUG_ATTR = "configDebug"; + private const string INTERNAL_DEBUG_ATTR = "debug"; + private const string CONFIG_UPDATE_MODE_ATTR = "update"; + private const string RENDERING_TYPE_ATTR = "renderingClass"; + private const string RENDERED_TYPE_ATTR = "renderedClass"; + + // flag used on the level element + private const string INHERITED = "inherited"; + + #endregion Private Constants + + #region Private Instance Fields + + /// + /// key: appenderName, value: appender. + /// + private Hashtable m_appenderBag; + + /// + /// The Hierarchy being configured. + /// + private readonly Hierarchy m_hierarchy; + + /// + /// The snapshot of the environment variables at configuration time, or null if an error has occured during querying them. + /// + private IDictionary m_environmentVariables; + + #endregion Private Instance Fields + } +} diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 32067969b..18dc01d0c 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -188,6 +188,10 @@ + + + + From 25921b721a3290efbdb3079765f7828ccc666794 Mon Sep 17 00:00:00 2001 From: attilah Date: Wed, 9 Mar 2011 10:41:11 +0100 Subject: [PATCH 03/11] Log4net configuration updated to use date based rolling file (and exclude time portion from filename). Bugfix related code formatting done on new files. --HG-- branch : contributions --- src/Orchard.Web/Config/log4net.config | 4 +- src/Orchard.Web/Orchard.Web.csproj | 12 +- src/Orchard/Logging/OrchardLog4netFactory.cs | 4 - src/Orchard/Logging/OrchardXmlConfigurator.cs | 29 +-- .../OrchardXmlHierarchyConfigurator.cs | 216 ++++++++---------- 5 files changed, 108 insertions(+), 157 deletions(-) diff --git a/src/Orchard.Web/Config/log4net.config b/src/Orchard.Web/Config/log4net.config index 3dc7e72bd..999e11599 100644 --- a/src/Orchard.Web/Config/log4net.config +++ b/src/Orchard.Web/Config/log4net.config @@ -54,7 +54,7 @@ - + @@ -73,7 +73,7 @@ - + diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index ec7b050fa..29223a2fb 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -195,17 +195,7 @@ - False - False - 30320 - /OrchardLocal - - - False - False - - - False + True diff --git a/src/Orchard/Logging/OrchardLog4netFactory.cs b/src/Orchard/Logging/OrchardLog4netFactory.cs index 5ab8c209d..4a5dd45d4 100644 --- a/src/Orchard/Logging/OrchardLog4netFactory.cs +++ b/src/Orchard/Logging/OrchardLog4netFactory.cs @@ -5,12 +5,8 @@ using System.Web; using System.Web.Hosting; using Castle.Core.Logging; -using Castle.Services.Logging.Log4netIntegration; using log4net; -using log4net.Config; - -using Orchard.Environment.Extensions.Helpers; namespace Orchard.Logging { public class OrchardLog4netFactory : AbstractLoggerFactory { diff --git a/src/Orchard/Logging/OrchardXmlConfigurator.cs b/src/Orchard/Logging/OrchardXmlConfigurator.cs index b301301c5..3d9d77ce2 100644 --- a/src/Orchard/Logging/OrchardXmlConfigurator.cs +++ b/src/Orchard/Logging/OrchardXmlConfigurator.cs @@ -1,20 +1,15 @@ using System; -using System.Xml; -using System.Collections; using System.IO; using System.Reflection; -using System.Threading; -using System.Net; +using System.Xml; using log4net; -using log4net.Appender; -using log4net.Util; using log4net.Repository; using log4net.Repository.Hierarchy; +using log4net.Util; namespace Orchard.Logging { public class OrchardXmlConfigurator { - #region Private Instance Constructors /// /// Private constructor @@ -22,10 +17,6 @@ namespace Orchard.Logging { private OrchardXmlConfigurator() { } - #endregion Protected Instance Constructors - - #region Configure static methods - /// /// Configures log4net using the specified configuration file. /// @@ -76,7 +67,7 @@ namespace Orchard.Logging { /// /// /// - static public void Configure(string configFilename) { + public static void Configure(string configFilename) { Configure(LogManager.GetRepository(Assembly.GetCallingAssembly()), configFilename); } @@ -94,7 +85,7 @@ namespace Orchard.Logging { /// Note that this method will NOT close the stream parameter. /// /// - static public void Configure(Stream configStream) { + public static void Configure(Stream configStream) { Configure(LogManager.GetRepository(Assembly.GetCallingAssembly()), configStream); } @@ -150,7 +141,7 @@ namespace Orchard.Logging { /// /// /// - static public void Configure(ILoggerRepository repository, string configFilename) { + public static void Configure(ILoggerRepository repository, string configFilename) { LogLog.Debug("XmlConfigurator: configuring repository [" + repository.Name + "] using file [" + configFilename + "]"); if (String.IsNullOrWhiteSpace(configFilename)) { @@ -214,7 +205,7 @@ namespace Orchard.Logging { /// Note that this method will NOT close the stream parameter. /// /// - static public void Configure(ILoggerRepository repository, Stream configStream) { + public static void Configure(ILoggerRepository repository, Stream configStream) { LogLog.Debug("XmlConfigurator: configuring repository [" + repository.Name + "] using stream"); if (configStream == null) { @@ -260,10 +251,6 @@ namespace Orchard.Logging { } } - #endregion Configure static methods - - #region Private Static Methods - /// /// Configures the specified repository using a log4net element. /// @@ -279,7 +266,7 @@ namespace Orchard.Logging { /// to load the configuration from an . /// /// - static private void ConfigureFromXml(ILoggerRepository repository, XmlElement element) { + private static void ConfigureFromXml(ILoggerRepository repository, XmlElement element) { if (element == null) { LogLog.Error("XmlConfigurator: ConfigureFromXml called with null 'element' parameter"); } @@ -319,7 +306,5 @@ namespace Orchard.Logging { } } } - - #endregion Private Static Methods } } diff --git a/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs b/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs index 156e277e7..0de2b8d63 100644 --- a/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs +++ b/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs @@ -5,10 +5,10 @@ using System.Reflection; using System.Xml; using log4net.Appender; -using log4net.Util; using log4net.Core; using log4net.ObjectRenderer; using log4net.Repository.Hierarchy; +using log4net.Util; namespace Orchard.Logging { /// @@ -27,7 +27,50 @@ namespace Orchard.Logging { Overwrite } - #region Public Instance Constructors + // String constants used while parsing the XML data + private const string ConfigurationTag = "log4net"; + private const string RendererTag = "renderer"; + private const string AppenderTag = "appender"; + private const string AppenderRefTag = "appender-ref"; + private const string ParamTag = "param"; + + // TODO: Deprecate use of category tags + private const string CategoryTag = "category"; + // TODO: Deprecate use of priority tag + private const string PriorityTag = "priority"; + + private const string LoggerTag = "logger"; + private const string NameAttr = "name"; + private const string TypeAttr = "type"; + private const string ValueAttr = "value"; + private const string RootTag = "root"; + private const string LevelTag = "level"; + private const string RefAttr = "ref"; + private const string AdditivityAttr = "additivity"; + private const string ThresholdAttr = "threshold"; + private const string ConfigDebugAttr = "configDebug"; + private const string InternalDebugAttr = "debug"; + private const string ConfigUpdateModeAttr = "update"; + private const string RenderingTypeAttr = "renderingClass"; + private const string RenderedTypeAttr = "renderedClass"; + + // flag used on the level element + private const string Inherited = "inherited"; + + /// + /// key: appenderName, value: appender. + /// + private Hashtable _appenderBag; + + /// + /// The Hierarchy being configured. + /// + private readonly Hierarchy _hierarchy; + + /// + /// The snapshot of the environment variables at configuration time, or null if an error has occured during querying them. + /// + private IDictionary _environmentVariables; /// /// Construct the configurator for a hierarchy @@ -40,14 +83,10 @@ namespace Orchard.Logging { /// /// public OrchardXmlHierarchyConfigurator(Hierarchy hierarchy) { - m_hierarchy = hierarchy; - m_appenderBag = new Hashtable(); + _hierarchy = hierarchy; + _appenderBag = new Hashtable(); } - #endregion Public Instance Constructors - - #region Public Instance Methods - /// /// Configure the hierarchy by parsing a DOM tree of XML elements. /// @@ -58,33 +97,33 @@ namespace Orchard.Logging { /// /// public void Configure(XmlElement element) { - if (element == null || m_hierarchy == null) { + if (element == null || _hierarchy == null) { return; } string rootElementName = element.LocalName; - if (rootElementName != CONFIGURATION_TAG) { - LogLog.Error("XmlHierarchyConfigurator: Xml element is - not a <" + CONFIGURATION_TAG + "> element."); + if (rootElementName != ConfigurationTag) { + LogLog.Error("XmlHierarchyConfigurator: Xml element is - not a <" + ConfigurationTag + "> element."); return; } if (!LogLog.InternalDebugging) { // Look for a debug attribute to enable internal debug - string debugAttribute = element.GetAttribute(INTERNAL_DEBUG_ATTR); - LogLog.Debug("XmlHierarchyConfigurator: " + INTERNAL_DEBUG_ATTR + " attribute [" + debugAttribute + "]."); + string debugAttribute = element.GetAttribute(InternalDebugAttr); + LogLog.Debug("XmlHierarchyConfigurator: " + InternalDebugAttr + " attribute [" + debugAttribute + "]."); if (debugAttribute.Length > 0 && debugAttribute != "null") { LogLog.InternalDebugging = OptionConverter.ToBoolean(debugAttribute, true); } else { - LogLog.Debug("XmlHierarchyConfigurator: Ignoring " + INTERNAL_DEBUG_ATTR + " attribute."); + LogLog.Debug("XmlHierarchyConfigurator: Ignoring " + InternalDebugAttr + " attribute."); } - string confDebug = element.GetAttribute(CONFIG_DEBUG_ATTR); + string confDebug = element.GetAttribute(ConfigDebugAttr); if (confDebug.Length > 0 && confDebug != "null") { - LogLog.Warn("XmlHierarchyConfigurator: The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated."); - LogLog.Warn("XmlHierarchyConfigurator: Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead."); + LogLog.Warn("XmlHierarchyConfigurator: The \"" + ConfigDebugAttr + "\" attribute is deprecated."); + LogLog.Warn("XmlHierarchyConfigurator: Use the \"" + InternalDebugAttr + "\" attribute instead."); LogLog.InternalDebugging = OptionConverter.ToBoolean(confDebug, true); } } @@ -93,14 +132,14 @@ namespace Orchard.Logging { ConfigUpdateMode configUpdateMode = ConfigUpdateMode.Merge; // Look for the config update attribute - string configUpdateModeAttribute = element.GetAttribute(CONFIG_UPDATE_MODE_ATTR); + string configUpdateModeAttribute = element.GetAttribute(ConfigUpdateModeAttr); if (configUpdateModeAttribute != null && configUpdateModeAttribute.Length > 0) { // Parse the attribute try { configUpdateMode = (ConfigUpdateMode)OptionConverter.ConvertStringTo(typeof(ConfigUpdateMode), configUpdateModeAttribute); } catch { - LogLog.Error("XmlHierarchyConfigurator: Invalid " + CONFIG_UPDATE_MODE_ATTR + " attribute value [" + configUpdateModeAttribute + "]"); + LogLog.Error("XmlHierarchyConfigurator: Invalid " + ConfigUpdateModeAttr + " attribute value [" + configUpdateModeAttribute + "]"); } } @@ -110,16 +149,16 @@ namespace Orchard.Logging { // Only reset configuration if overwrite flag specified if (configUpdateMode == ConfigUpdateMode.Overwrite) { // Reset to original unset configuration - m_hierarchy.ResetConfiguration(); + _hierarchy.ResetConfiguration(); LogLog.Debug("XmlHierarchyConfigurator: Configuration reset before reading config."); } // Try to retrieve the environment variables try { - m_environmentVariables = System.Environment.GetEnvironmentVariables(); + _environmentVariables = System.Environment.GetEnvironmentVariables(); } catch (System.Security.SecurityException) { - m_environmentVariables = null; + _environmentVariables = null; // This security exception will occur if the caller does not have // unrestricted environment permission. If this occurs the expansion @@ -136,37 +175,37 @@ namespace Orchard.Logging { if (currentNode.NodeType == XmlNodeType.Element) { XmlElement currentElement = (XmlElement)currentNode; - if (currentElement.LocalName == LOGGER_TAG) { + if (currentElement.LocalName == LoggerTag) { ParseLogger(currentElement); } - else if (currentElement.LocalName == CATEGORY_TAG) { + else if (currentElement.LocalName == CategoryTag) { // TODO: deprecated use of category ParseLogger(currentElement); } - else if (currentElement.LocalName == ROOT_TAG) { + else if (currentElement.LocalName == RootTag) { ParseRoot(currentElement); } - else if (currentElement.LocalName == RENDERER_TAG) { + else if (currentElement.LocalName == RendererTag) { ParseRenderer(currentElement); } - else if (currentElement.LocalName == APPENDER_TAG) { + else if (currentElement.LocalName == AppenderTag) { // We ignore appenders in this pass. They will // be found and loaded if they are referenced. } else { // Read the param tags and set properties on the hierarchy - SetParameter(currentElement, m_hierarchy); + SetParameter(currentElement, _hierarchy); } } } // Lastly set the hierarchy threshold - string thresholdStr = element.GetAttribute(THRESHOLD_ATTR); + string thresholdStr = element.GetAttribute(ThresholdAttr); LogLog.Debug("XmlHierarchyConfigurator: Hierarchy Threshold [" + thresholdStr + "]"); if (thresholdStr.Length > 0 && thresholdStr != "null") { Level thresholdLevel = (Level)ConvertStringTo(typeof(Level), thresholdStr); if (thresholdLevel != null) { - m_hierarchy.Threshold = thresholdLevel; + _hierarchy.Threshold = thresholdLevel; } else { LogLog.Warn("XmlHierarchyConfigurator: Unable to set hierarchy threshold using value [" + thresholdStr + "] (with acceptable conversion types)"); @@ -176,10 +215,6 @@ namespace Orchard.Logging { // Done reading config } - #endregion Public Instance Methods - - #region Protected Instance Methods - /// /// Parse appenders by IDREF. /// @@ -192,9 +227,9 @@ namespace Orchard.Logging { /// /// protected IAppender FindAppenderByReference(XmlElement appenderRef) { - string appenderName = appenderRef.GetAttribute(REF_ATTR); + string appenderName = appenderRef.GetAttribute(RefAttr); - IAppender appender = (IAppender)m_appenderBag[appenderName]; + IAppender appender = (IAppender)_appenderBag[appenderName]; if (appender != null) { return appender; } @@ -203,7 +238,7 @@ namespace Orchard.Logging { XmlElement element = null; if (appenderName != null && appenderName.Length > 0) { - foreach (XmlElement curAppenderElement in appenderRef.OwnerDocument.GetElementsByTagName(APPENDER_TAG)) { + foreach (XmlElement curAppenderElement in appenderRef.OwnerDocument.GetElementsByTagName(AppenderTag)) { if (curAppenderElement.GetAttribute("name") == appenderName) { element = curAppenderElement; break; @@ -218,7 +253,7 @@ namespace Orchard.Logging { else { appender = ParseAppender(element); if (appender != null) { - m_appenderBag[appenderName] = appender; + _appenderBag[appenderName] = appender; } return appender; } @@ -237,8 +272,8 @@ namespace Orchard.Logging { /// /// protected IAppender ParseAppender(XmlElement appenderElement) { - string appenderName = appenderElement.GetAttribute(NAME_ATTR); - string typeName = appenderElement.GetAttribute(TYPE_ATTR); + string appenderName = appenderElement.GetAttribute(NameAttr); + string typeName = appenderElement.GetAttribute(TypeAttr); LogLog.Debug("XmlHierarchyConfigurator: Loading Appender [" + appenderName + "] type: [" + typeName + "]"); try { @@ -251,8 +286,8 @@ namespace Orchard.Logging { XmlElement currentElement = (XmlElement)currentNode; // Look for the appender ref tag - if (currentElement.LocalName == APPENDER_REF_TAG) { - string refName = currentElement.GetAttribute(REF_ATTR); + if (currentElement.LocalName == AppenderRefTag) { + string refName = currentElement.GetAttribute(RefAttr); IAppenderAttachable appenderContainer = appender as IAppenderAttachable; if (appenderContainer != null) { @@ -301,16 +336,16 @@ namespace Orchard.Logging { /// protected void ParseLogger(XmlElement loggerElement) { // Create a new log4net.Logger object from the element. - string loggerName = loggerElement.GetAttribute(NAME_ATTR); + string loggerName = loggerElement.GetAttribute(NameAttr); LogLog.Debug("XmlHierarchyConfigurator: Retrieving an instance of log4net.Repository.Logger for logger [" + loggerName + "]."); - Logger log = m_hierarchy.GetLogger(loggerName) as Logger; + Logger log = _hierarchy.GetLogger(loggerName) as Logger; // Setting up a logger needs to be an atomic operation, in order // to protect potential log operations while logger // configuration is in progress. lock (log) { - bool additivity = OptionConverter.ToBoolean(loggerElement.GetAttribute(ADDITIVITY_ATTR), true); + bool additivity = OptionConverter.ToBoolean(loggerElement.GetAttribute(AdditivityAttr), true); LogLog.Debug("XmlHierarchyConfigurator: Setting [" + log.Name + "] additivity to [" + additivity + "]."); log.Additivity = additivity; @@ -328,7 +363,7 @@ namespace Orchard.Logging { /// /// protected void ParseRoot(XmlElement rootElement) { - Logger root = m_hierarchy.Root; + Logger root = _hierarchy.Root; // logger configuration needs to be atomic lock (root) { ParseChildrenOfLoggerElement(rootElement, root, true); @@ -355,9 +390,9 @@ namespace Orchard.Logging { if (currentNode.NodeType == XmlNodeType.Element) { XmlElement currentElement = (XmlElement)currentNode; - if (currentElement.LocalName == APPENDER_REF_TAG) { + if (currentElement.LocalName == AppenderRefTag) { IAppender appender = FindAppenderByReference(currentElement); - string refName = currentElement.GetAttribute(REF_ATTR); + string refName = currentElement.GetAttribute(RefAttr); if (appender != null) { LogLog.Debug("XmlHierarchyConfigurator: Adding appender named [" + refName + "] to logger [" + log.Name + "]."); log.AddAppender(appender); @@ -366,7 +401,7 @@ namespace Orchard.Logging { LogLog.Error("XmlHierarchyConfigurator: Appender named [" + refName + "] not found."); } } - else if (currentElement.LocalName == LEVEL_TAG || currentElement.LocalName == PRIORITY_TAG) { + else if (currentElement.LocalName == LevelTag || currentElement.LocalName == PriorityTag) { ParseLevel(currentElement, log, isRoot); } else { @@ -391,8 +426,8 @@ namespace Orchard.Logging { /// /// protected void ParseRenderer(XmlElement element) { - string renderingClassName = element.GetAttribute(RENDERING_TYPE_ATTR); - string renderedClassName = element.GetAttribute(RENDERED_TYPE_ATTR); + string renderingClassName = element.GetAttribute(RenderingTypeAttr); + string renderedClassName = element.GetAttribute(RenderedTypeAttr); LogLog.Debug("XmlHierarchyConfigurator: Rendering class [" + renderingClassName + "], Rendered class [" + renderedClassName + "]."); IObjectRenderer renderer = (IObjectRenderer)OptionConverter.InstantiateByClassName(renderingClassName, typeof(IObjectRenderer), null); @@ -402,7 +437,7 @@ namespace Orchard.Logging { } else { try { - m_hierarchy.RendererMap.Put(SystemInfo.GetTypeFromString(renderedClassName, true, true), renderer); + _hierarchy.RendererMap.Put(SystemInfo.GetTypeFromString(renderedClassName, true, true), renderer); } catch (Exception e) { LogLog.Error("XmlHierarchyConfigurator: Could not find class [" + renderedClassName + "].", e); @@ -427,10 +462,10 @@ namespace Orchard.Logging { loggerName = "root"; } - string levelStr = element.GetAttribute(VALUE_ATTR); + string levelStr = element.GetAttribute(ValueAttr); LogLog.Debug("XmlHierarchyConfigurator: Logger [" + loggerName + "] Level string is [" + levelStr + "]."); - if (INHERITED == levelStr) { + if (Inherited == levelStr) { if (isRoot) { LogLog.Error("XmlHierarchyConfigurator: Root level cannot be inherited. Ignoring directive."); } @@ -468,10 +503,10 @@ namespace Orchard.Logging { /// protected void SetParameter(XmlElement element, object target) { // Get the property name - string name = element.GetAttribute(NAME_ATTR); + string name = element.GetAttribute(NameAttr); // If the name attribute does not exist then use the name of the element - if (element.LocalName != PARAM_TAG || name == null || name.Length == 0) { + if (element.LocalName != ParamTag || name == null || name.Length == 0) { name = element.LocalName; } @@ -505,8 +540,8 @@ namespace Orchard.Logging { else { string propertyValue = null; - if (element.GetAttributeNode(VALUE_ATTR) != null) { - propertyValue = element.GetAttribute(VALUE_ATTR); + if (element.GetAttributeNode(ValueAttr) != null) { + propertyValue = element.GetAttribute(ValueAttr); } else if (element.HasChildNodes) { // Concatenate the CDATA and Text nodes together @@ -523,15 +558,15 @@ namespace Orchard.Logging { } if (propertyValue != null) { - if (m_environmentVariables != null) { + if (_environmentVariables != null) { // Expand environment variables in the string. - propertyValue = OptionConverter.SubstituteVariables(propertyValue, m_environmentVariables); + propertyValue = OptionConverter.SubstituteVariables(propertyValue, _environmentVariables); } Type parsedObjectConversionTargetType = null; // Check if a specific subtype is specified on the element using the 'type' attribute - string subTypeString = element.GetAttribute(TYPE_ATTR); + string subTypeString = element.GetAttribute(TypeAttr); if (subTypeString != null && subTypeString.Length > 0) { // Read the explicit subtype try { @@ -738,7 +773,7 @@ namespace Orchard.Logging { // Hack to allow use of Level in property if (typeof(Level) == type) { // Property wants a level - Level levelValue = m_hierarchy.LevelMap[value]; + Level levelValue = _hierarchy.LevelMap[value]; if (levelValue == null) { LogLog.Error("XmlHierarchyConfigurator: Unknown Level Specified [" + value + "]"); @@ -772,7 +807,7 @@ namespace Orchard.Logging { Type objectType = null; // Get the object type - string objectTypeString = element.GetAttribute(TYPE_ATTR); + string objectTypeString = element.GetAttribute(TypeAttr); if (objectTypeString == null || objectTypeString.Length == 0) { if (defaultTargetType == null) { LogLog.Error("XmlHierarchyConfigurator: Object type not specified. Cannot create object of type [" + typeConstraint.FullName + "]. Missing Value or Type."); @@ -843,60 +878,5 @@ namespace Orchard.Logging { return createdObject; } } - - #endregion Protected Instance Methods - - #region Private Constants - - // String constants used while parsing the XML data - private const string CONFIGURATION_TAG = "log4net"; - private const string RENDERER_TAG = "renderer"; - private const string APPENDER_TAG = "appender"; - private const string APPENDER_REF_TAG = "appender-ref"; - private const string PARAM_TAG = "param"; - - // TODO: Deprecate use of category tags - private const string CATEGORY_TAG = "category"; - // TODO: Deprecate use of priority tag - private const string PRIORITY_TAG = "priority"; - - private const string LOGGER_TAG = "logger"; - private const string NAME_ATTR = "name"; - private const string TYPE_ATTR = "type"; - private const string VALUE_ATTR = "value"; - private const string ROOT_TAG = "root"; - private const string LEVEL_TAG = "level"; - private const string REF_ATTR = "ref"; - private const string ADDITIVITY_ATTR = "additivity"; - private const string THRESHOLD_ATTR = "threshold"; - private const string CONFIG_DEBUG_ATTR = "configDebug"; - private const string INTERNAL_DEBUG_ATTR = "debug"; - private const string CONFIG_UPDATE_MODE_ATTR = "update"; - private const string RENDERING_TYPE_ATTR = "renderingClass"; - private const string RENDERED_TYPE_ATTR = "renderedClass"; - - // flag used on the level element - private const string INHERITED = "inherited"; - - #endregion Private Constants - - #region Private Instance Fields - - /// - /// key: appenderName, value: appender. - /// - private Hashtable m_appenderBag; - - /// - /// The Hierarchy being configured. - /// - private readonly Hierarchy m_hierarchy; - - /// - /// The snapshot of the environment variables at configuration time, or null if an error has occured during querying them. - /// - private IDictionary m_environmentVariables; - - #endregion Private Instance Fields } } From c2bb9372e73d9a50d91cb717b30378c63c51c6f4 Mon Sep 17 00:00:00 2001 From: attilah Date: Wed, 9 Mar 2011 17:31:53 +0100 Subject: [PATCH 04/11] Fixed: #16884 - SessionConfigurationCache throws SecurityExceptions at startup in Medium Trust --HG-- branch : contributions --- src/Orchard/Data/SessionConfigurationCache.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Orchard/Data/SessionConfigurationCache.cs b/src/Orchard/Data/SessionConfigurationCache.cs index 2bc3a3a7c..00c529904 100644 --- a/src/Orchard/Data/SessionConfigurationCache.cs +++ b/src/Orchard/Data/SessionConfigurationCache.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using NHibernate.Cfg; +using Orchard.Environment; using Orchard.Environment.Configuration; using Orchard.Environment.ShellBuilders.Models; using Orchard.FileSystems.AppData; @@ -14,11 +15,13 @@ namespace Orchard.Data { private readonly ShellSettings _shellSettings; private readonly ShellBlueprint _shellBlueprint; private readonly IAppDataFolder _appDataFolder; + private readonly IHostEnvironment _hostEnvironment; - public SessionConfigurationCache(ShellSettings shellSettings, ShellBlueprint shellBlueprint, IAppDataFolder appDataFolder) { + public SessionConfigurationCache(ShellSettings shellSettings, ShellBlueprint shellBlueprint, IAppDataFolder appDataFolder, IHostEnvironment hostEnvironment) { _shellSettings = shellSettings; _shellBlueprint = shellBlueprint; _appDataFolder = appDataFolder; + _hostEnvironment = hostEnvironment; Logger = NullLogger.Instance; } @@ -51,6 +54,9 @@ namespace Orchard.Data { } private void StoreConfiguration(ConfigurationCache cache) { + if (!_hostEnvironment.IsFullTrust) + return; + var pathName = GetPathName(_shellSettings.Name); try { @@ -70,6 +76,9 @@ namespace Orchard.Data { } private ConfigurationCache ReadConfiguration(string hash) { + if (!_hostEnvironment.IsFullTrust) + return null; + var pathName = GetPathName(_shellSettings.Name); if (!_appDataFolder.FileExists(pathName)) From 5b20c24f1b2020e22865e15e7eee450746305e26 Mon Sep 17 00:00:00 2001 From: Suha Can Date: Wed, 9 Mar 2011 14:08:13 -0800 Subject: [PATCH 05/11] Setting some project properties back in Orchard.Web.csproj. --HG-- branch : contributions --- src/Orchard.Web/Orchard.Web.csproj | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index 29223a2fb..ec7b050fa 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -195,7 +195,17 @@ - True + False + False + 30320 + /OrchardLocal + + + False + False + + + False From 04955509caccb4ee01ad15ed67384c1e64609cd2 Mon Sep 17 00:00:00 2001 From: Suha Can Date: Wed, 9 Mar 2011 14:34:47 -0800 Subject: [PATCH 06/11] Cleanup. --HG-- branch : contributions --- src/Orchard/Logging/OrchardLog4netLogger.cs | 16 +- src/Orchard/Logging/OrchardXmlConfigurator.cs | 22 +- .../OrchardXmlHierarchyConfigurator.cs | 208 ++++++++---------- 3 files changed, 106 insertions(+), 140 deletions(-) diff --git a/src/Orchard/Logging/OrchardLog4netLogger.cs b/src/Orchard/Logging/OrchardLog4netLogger.cs index 8998fd0b1..d204495a8 100644 --- a/src/Orchard/Logging/OrchardLog4netLogger.cs +++ b/src/Orchard/Logging/OrchardLog4netLogger.cs @@ -1,18 +1,4 @@ -// Copyright 2004-2010 Castle Project - http://www.castleproject.org/ -// -// 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. - -using System; +using System; using System.Globalization; using log4net; diff --git a/src/Orchard/Logging/OrchardXmlConfigurator.cs b/src/Orchard/Logging/OrchardXmlConfigurator.cs index 3d9d77ce2..965f389f9 100644 --- a/src/Orchard/Logging/OrchardXmlConfigurator.cs +++ b/src/Orchard/Logging/OrchardXmlConfigurator.cs @@ -155,7 +155,7 @@ namespace Orchard.Logging { FileStream fs = null; // Try hard to open the file - for (int retry = 5; --retry >= 0; ) { + for (var retry = 5; --retry >= 0; ) { try { fs = new FileStream(configFilename, FileMode.Open, FileAccess.Read, FileShare.Read); break; @@ -213,15 +213,13 @@ namespace Orchard.Logging { } else { // Load the config file into a document - XmlDocument doc = new XmlDocument(); + var doc = new XmlDocument(); try { // Create a text reader for the file stream - XmlTextReader xmlReader = new XmlTextReader(configStream); - xmlReader.DtdProcessing = DtdProcessing.Parse; + var xmlReader = new XmlTextReader(configStream) { DtdProcessing = DtdProcessing.Parse }; // Specify that the reader should not perform validation - XmlReaderSettings settings = new XmlReaderSettings(); - settings.ValidationType = ValidationType.None; + var settings = new XmlReaderSettings { ValidationType = ValidationType.None }; // load the data into the document doc.Load(xmlReader); @@ -237,7 +235,7 @@ namespace Orchard.Logging { LogLog.Debug("XmlConfigurator: loading XML configuration"); // Configure using the 'log4net' element - XmlNodeList configNodeList = doc.GetElementsByTagName("log4net"); + var configNodeList = doc.GetElementsByTagName("log4net"); if (configNodeList.Count == 0) { LogLog.Debug("XmlConfigurator: XML configuration does not contain a element. Configuration Aborted."); } @@ -282,22 +280,22 @@ namespace Orchard.Logging { // // Needed to fire configuration changed event - LoggerRepositorySkeleton repositorySkeleton = repository as LoggerRepositorySkeleton; + var repositorySkeleton = repository as LoggerRepositorySkeleton; // Needed to XmlHierarchyConfigurator - Hierarchy hierarchy = repository as Hierarchy; + var hierarchy = repository as Hierarchy; if (repositorySkeleton == null || hierarchy == null) { LogLog.Warn("XmlConfigurator: Repository [" + repository + "] does not support the XmlConfigurator"); } else { - OrchardXmlHierarchyConfigurator configurator = new OrchardXmlHierarchyConfigurator(hierarchy); + var configurator = new OrchardXmlHierarchyConfigurator(hierarchy); // Copy the xml data into the root of a new document // this isolates the xml config data from the rest of // the document - XmlDocument newDoc = new XmlDocument(); - XmlElement newElement = (XmlElement)newDoc.AppendChild(newDoc.ImportNode(element, true)); + var newDoc = new XmlDocument(); + var newElement = (XmlElement)newDoc.AppendChild(newDoc.ImportNode(element, true)); // Pass the configurator the config element configurator.Configure(newElement); diff --git a/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs b/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs index 0de2b8d63..a04774c38 100644 --- a/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs +++ b/src/Orchard/Logging/OrchardXmlHierarchyConfigurator.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Globalization; +using System.Linq; using System.Reflection; using System.Xml; @@ -101,7 +102,7 @@ namespace Orchard.Logging { return; } - string rootElementName = element.LocalName; + var rootElementName = element.LocalName; if (rootElementName != ConfigurationTag) { LogLog.Error("XmlHierarchyConfigurator: Xml element is - not a <" + ConfigurationTag + "> element."); @@ -110,7 +111,7 @@ namespace Orchard.Logging { if (!LogLog.InternalDebugging) { // Look for a debug attribute to enable internal debug - string debugAttribute = element.GetAttribute(InternalDebugAttr); + var debugAttribute = element.GetAttribute(InternalDebugAttr); LogLog.Debug("XmlHierarchyConfigurator: " + InternalDebugAttr + " attribute [" + debugAttribute + "]."); if (debugAttribute.Length > 0 && debugAttribute != "null") { @@ -120,7 +121,7 @@ namespace Orchard.Logging { LogLog.Debug("XmlHierarchyConfigurator: Ignoring " + InternalDebugAttr + " attribute."); } - string confDebug = element.GetAttribute(ConfigDebugAttr); + var confDebug = element.GetAttribute(ConfigDebugAttr); if (confDebug.Length > 0 && confDebug != "null") { LogLog.Warn("XmlHierarchyConfigurator: The \"" + ConfigDebugAttr + "\" attribute is deprecated."); LogLog.Warn("XmlHierarchyConfigurator: Use the \"" + InternalDebugAttr + "\" attribute instead."); @@ -129,11 +130,11 @@ namespace Orchard.Logging { } // Default mode is merge - ConfigUpdateMode configUpdateMode = ConfigUpdateMode.Merge; + var configUpdateMode = ConfigUpdateMode.Merge; // Look for the config update attribute - string configUpdateModeAttribute = element.GetAttribute(ConfigUpdateModeAttr); - if (configUpdateModeAttribute != null && configUpdateModeAttribute.Length > 0) { + var configUpdateModeAttribute = element.GetAttribute(ConfigUpdateModeAttr); + if (!String.IsNullOrEmpty(configUpdateModeAttribute)) { // Parse the attribute try { configUpdateMode = (ConfigUpdateMode)OptionConverter.ConvertStringTo(typeof(ConfigUpdateMode), configUpdateModeAttribute); @@ -144,7 +145,7 @@ namespace Orchard.Logging { } // IMPL: The IFormatProvider argument to Enum.ToString() is deprecated in .NET 2.0 - LogLog.Debug("XmlHierarchyConfigurator: Configuration update mode [" + configUpdateMode.ToString() + "]."); + LogLog.Debug("XmlHierarchyConfigurator: Configuration update mode [" + configUpdateMode + "]."); // Only reset configuration if overwrite flag specified if (configUpdateMode == ConfigUpdateMode.Overwrite) { @@ -173,7 +174,7 @@ namespace Orchard.Logging { foreach (XmlNode currentNode in element.ChildNodes) { if (currentNode.NodeType == XmlNodeType.Element) { - XmlElement currentElement = (XmlElement)currentNode; + var currentElement = (XmlElement)currentNode; if (currentElement.LocalName == LoggerTag) { ParseLogger(currentElement); @@ -203,7 +204,7 @@ namespace Orchard.Logging { string thresholdStr = element.GetAttribute(ThresholdAttr); LogLog.Debug("XmlHierarchyConfigurator: Hierarchy Threshold [" + thresholdStr + "]"); if (thresholdStr.Length > 0 && thresholdStr != "null") { - Level thresholdLevel = (Level)ConvertStringTo(typeof(Level), thresholdStr); + var thresholdLevel = (Level)ConvertStringTo(typeof(Level), thresholdStr); if (thresholdLevel != null) { _hierarchy.Threshold = thresholdLevel; } @@ -227,37 +228,34 @@ namespace Orchard.Logging { /// /// protected IAppender FindAppenderByReference(XmlElement appenderRef) { - string appenderName = appenderRef.GetAttribute(RefAttr); + var appenderName = appenderRef.GetAttribute(RefAttr); IAppender appender = (IAppender)_appenderBag[appenderName]; if (appender != null) { return appender; } - else { - // Find the element with that id - XmlElement element = null; + // Find the element with that id + XmlElement element = null; - if (appenderName != null && appenderName.Length > 0) { - foreach (XmlElement curAppenderElement in appenderRef.OwnerDocument.GetElementsByTagName(AppenderTag)) { - if (curAppenderElement.GetAttribute("name") == appenderName) { - element = curAppenderElement; - break; - } + if (!String.IsNullOrEmpty(appenderName)) { + foreach (XmlElement curAppenderElement in appenderRef.OwnerDocument.GetElementsByTagName(AppenderTag)) { + if (curAppenderElement.GetAttribute("name") != appenderName) { + continue; } - } - - if (element == null) { - LogLog.Error("XmlHierarchyConfigurator: No appender named [" + appenderName + "] could be found."); - return null; - } - else { - appender = ParseAppender(element); - if (appender != null) { - _appenderBag[appenderName] = appender; - } - return appender; + element = curAppenderElement; + break; } } + + if (element == null) { + LogLog.Error("XmlHierarchyConfigurator: No appender named [" + appenderName + "] could be found."); + return null; + } + appender = ParseAppender(element); + if (appender != null) { + _appenderBag[appenderName] = appender; + } + return appender; } /// @@ -272,28 +270,28 @@ namespace Orchard.Logging { /// /// protected IAppender ParseAppender(XmlElement appenderElement) { - string appenderName = appenderElement.GetAttribute(NameAttr); - string typeName = appenderElement.GetAttribute(TypeAttr); + var appenderName = appenderElement.GetAttribute(NameAttr); + var typeName = appenderElement.GetAttribute(TypeAttr); LogLog.Debug("XmlHierarchyConfigurator: Loading Appender [" + appenderName + "] type: [" + typeName + "]"); try { - IAppender appender = (IAppender)Activator.CreateInstance(SystemInfo.GetTypeFromString(typeName, true, true)); + var appender = (IAppender)Activator.CreateInstance(SystemInfo.GetTypeFromString(typeName, true, true)); appender.Name = appenderName; foreach (XmlNode currentNode in appenderElement.ChildNodes) { /* We're only interested in Elements */ if (currentNode.NodeType == XmlNodeType.Element) { - XmlElement currentElement = (XmlElement)currentNode; + var currentElement = (XmlElement)currentNode; // Look for the appender ref tag if (currentElement.LocalName == AppenderRefTag) { - string refName = currentElement.GetAttribute(RefAttr); + var refName = currentElement.GetAttribute(RefAttr); - IAppenderAttachable appenderContainer = appender as IAppenderAttachable; + var appenderContainer = appender as IAppenderAttachable; if (appenderContainer != null) { LogLog.Debug("XmlHierarchyConfigurator: Attaching appender named [" + refName + "] to appender named [" + appender.Name + "]."); - IAppender referencedAppender = FindAppenderByReference(currentElement); + var referencedAppender = FindAppenderByReference(currentElement); if (referencedAppender != null) { appenderContainer.AddAppender(referencedAppender); } @@ -309,7 +307,7 @@ namespace Orchard.Logging { } } - IOptionHandler optionHandler = appender as IOptionHandler; + var optionHandler = appender as IOptionHandler; if (optionHandler != null) { optionHandler.ActivateOptions(); } @@ -336,16 +334,19 @@ namespace Orchard.Logging { /// protected void ParseLogger(XmlElement loggerElement) { // Create a new log4net.Logger object from the element. - string loggerName = loggerElement.GetAttribute(NameAttr); + var loggerName = loggerElement.GetAttribute(NameAttr); LogLog.Debug("XmlHierarchyConfigurator: Retrieving an instance of log4net.Repository.Logger for logger [" + loggerName + "]."); - Logger log = _hierarchy.GetLogger(loggerName) as Logger; + var log = _hierarchy.GetLogger(loggerName) as Logger; // Setting up a logger needs to be an atomic operation, in order // to protect potential log operations while logger // configuration is in progress. + if (log == null) { + return; + } lock (log) { - bool additivity = OptionConverter.ToBoolean(loggerElement.GetAttribute(AdditivityAttr), true); + var additivity = OptionConverter.ToBoolean(loggerElement.GetAttribute(AdditivityAttr), true); LogLog.Debug("XmlHierarchyConfigurator: Setting [" + log.Name + "] additivity to [" + additivity + "]."); log.Additivity = additivity; @@ -363,7 +364,7 @@ namespace Orchard.Logging { /// /// protected void ParseRoot(XmlElement rootElement) { - Logger root = _hierarchy.Root; + var root = _hierarchy.Root; // logger configuration needs to be atomic lock (root) { ParseChildrenOfLoggerElement(rootElement, root, true); @@ -388,11 +389,11 @@ namespace Orchard.Logging { foreach (XmlNode currentNode in catElement.ChildNodes) { if (currentNode.NodeType == XmlNodeType.Element) { - XmlElement currentElement = (XmlElement)currentNode; + var currentElement = (XmlElement)currentNode; if (currentElement.LocalName == AppenderRefTag) { - IAppender appender = FindAppenderByReference(currentElement); - string refName = currentElement.GetAttribute(RefAttr); + var appender = FindAppenderByReference(currentElement); + var refName = currentElement.GetAttribute(RefAttr); if (appender != null) { LogLog.Debug("XmlHierarchyConfigurator: Adding appender named [" + refName + "] to logger [" + log.Name + "]."); log.AddAppender(appender); @@ -410,7 +411,7 @@ namespace Orchard.Logging { } } - IOptionHandler optionHandler = log as IOptionHandler; + var optionHandler = log as IOptionHandler; if (optionHandler != null) { optionHandler.ActivateOptions(); } @@ -426,22 +427,20 @@ namespace Orchard.Logging { /// /// protected void ParseRenderer(XmlElement element) { - string renderingClassName = element.GetAttribute(RenderingTypeAttr); - string renderedClassName = element.GetAttribute(RenderedTypeAttr); + var renderingClassName = element.GetAttribute(RenderingTypeAttr); + var renderedClassName = element.GetAttribute(RenderedTypeAttr); LogLog.Debug("XmlHierarchyConfigurator: Rendering class [" + renderingClassName + "], Rendered class [" + renderedClassName + "]."); - IObjectRenderer renderer = (IObjectRenderer)OptionConverter.InstantiateByClassName(renderingClassName, typeof(IObjectRenderer), null); + var renderer = (IObjectRenderer)OptionConverter.InstantiateByClassName(renderingClassName, typeof(IObjectRenderer), null); if (renderer == null) { LogLog.Error("XmlHierarchyConfigurator: Could not instantiate renderer [" + renderingClassName + "]."); return; } - else { - try { - _hierarchy.RendererMap.Put(SystemInfo.GetTypeFromString(renderedClassName, true, true), renderer); - } - catch (Exception e) { - LogLog.Error("XmlHierarchyConfigurator: Could not find class [" + renderedClassName + "].", e); - } + try { + _hierarchy.RendererMap.Put(SystemInfo.GetTypeFromString(renderedClassName, true, true), renderer); + } + catch (Exception e) { + LogLog.Error("XmlHierarchyConfigurator: Could not find class [" + renderedClassName + "].", e); } } @@ -457,12 +456,12 @@ namespace Orchard.Logging { /// /// protected void ParseLevel(XmlElement element, Logger log, bool isRoot) { - string loggerName = log.Name; + var loggerName = log.Name; if (isRoot) { loggerName = "root"; } - string levelStr = element.GetAttribute(ValueAttr); + var levelStr = element.GetAttribute(ValueAttr); LogLog.Debug("XmlHierarchyConfigurator: Logger [" + loggerName + "] Level string is [" + levelStr + "]."); if (Inherited == levelStr) { @@ -503,22 +502,21 @@ namespace Orchard.Logging { /// protected void SetParameter(XmlElement element, object target) { // Get the property name - string name = element.GetAttribute(NameAttr); + var name = element.GetAttribute(NameAttr); // If the name attribute does not exist then use the name of the element - if (element.LocalName != ParamTag || name == null || name.Length == 0) { + if (element.LocalName != ParamTag || String.IsNullOrEmpty(name)) { name = element.LocalName; } // Look for the property on the target object - Type targetType = target.GetType(); + var targetType = target.GetType(); Type propertyType = null; - PropertyInfo propInfo = null; MethodInfo methInfo = null; // Try to find a writable property - propInfo = targetType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase); + var propInfo = targetType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase); if (propInfo != null && propInfo.CanWrite) { // found a property propertyType = propInfo.PropertyType; @@ -535,7 +533,7 @@ namespace Orchard.Logging { } if (propertyType == null) { - LogLog.Error("XmlHierarchyConfigurator: Cannot find Property [" + name + "] to set object on [" + target.ToString() + "]"); + LogLog.Error("XmlHierarchyConfigurator: Cannot find Property [" + name + "] to set object on [" + target + "]"); } else { string propertyValue = null; @@ -566,11 +564,11 @@ namespace Orchard.Logging { Type parsedObjectConversionTargetType = null; // Check if a specific subtype is specified on the element using the 'type' attribute - string subTypeString = element.GetAttribute(TypeAttr); - if (subTypeString != null && subTypeString.Length > 0) { + var subTypeString = element.GetAttribute(TypeAttr); + if (!String.IsNullOrEmpty(subTypeString)) { // Read the explicit subtype try { - Type subType = SystemInfo.GetTypeFromString(subTypeString, true, true); + var subType = SystemInfo.GetTypeFromString(subTypeString, true, true); LogLog.Debug("XmlHierarchyConfigurator: Parameter [" + name + "] specified subtype [" + subType.FullName + "]"); @@ -601,7 +599,7 @@ namespace Orchard.Logging { // Now try to convert the string value to an acceptable type // to pass to this property. - object convertedValue = ConvertStringTo(propertyType, propertyValue); + var convertedValue = ConvertStringTo(propertyType, propertyValue); // Check if we need to do an additional conversion if (convertedValue != null && parsedObjectConversionTargetType != null) { @@ -612,7 +610,7 @@ namespace Orchard.Logging { if (convertedValue != null) { if (propInfo != null) { // Got a converted result - LogLog.Debug("XmlHierarchyConfigurator: Setting Property [" + propInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue.ToString() + "]"); + LogLog.Debug("XmlHierarchyConfigurator: Setting Property [" + propInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue + "]"); try { // Pass to the property @@ -624,11 +622,11 @@ namespace Orchard.Logging { } else if (methInfo != null) { // Got a converted result - LogLog.Debug("XmlHierarchyConfigurator: Setting Collection Property [" + methInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue.ToString() + "]"); + LogLog.Debug("XmlHierarchyConfigurator: Setting Collection Property [" + methInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue + "]"); try { // Pass to the property - methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new object[] { convertedValue }, CultureInfo.InvariantCulture); + methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new[] { convertedValue }, CultureInfo.InvariantCulture); } catch (TargetInvocationException targetInvocationEx) { LogLog.Error("XmlHierarchyConfigurator: Failed to set parameter [" + name + "] on object [" + target + "] using value [" + convertedValue + "]", targetInvocationEx.InnerException); @@ -640,7 +638,7 @@ namespace Orchard.Logging { } } else { - object createdObject = null; + object createdObject; if (propertyType == typeof(string) && !HasAttributesOrElements(element)) { // If the property is a string and the element is empty (no attributes @@ -682,7 +680,7 @@ namespace Orchard.Logging { try { // Pass to the property - methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new object[] { createdObject }, CultureInfo.InvariantCulture); + methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new[] { createdObject }, CultureInfo.InvariantCulture); } catch (TargetInvocationException targetInvocationEx) { LogLog.Error("XmlHierarchyConfigurator: Failed to set parameter [" + methInfo.Name + "] on object [" + target + "] using value [" + createdObject + "]", targetInvocationEx.InnerException); @@ -698,13 +696,8 @@ namespace Orchard.Logging { /// /// the element to inspect /// true if the element has any attributes or child elements, false otherwise - private bool HasAttributesOrElements(XmlElement element) { - foreach (XmlNode node in element.ChildNodes) { - if (node.NodeType == XmlNodeType.Attribute || node.NodeType == XmlNodeType.Element) { - return true; - } - } - return false; + private static bool HasAttributesOrElements(XmlElement element) { + return element.ChildNodes.Cast().Any(node => node.NodeType == XmlNodeType.Attribute || node.NodeType == XmlNodeType.Element); } /// @@ -714,7 +707,7 @@ namespace Orchard.Logging { /// true if the type is creatable using a default constructor, false otherwise private static bool IsTypeConstructible(Type type) { if (type.IsClass && !type.IsAbstract) { - ConstructorInfo defaultConstructor = type.GetConstructor(new Type[0]); + var defaultConstructor = type.GetConstructor(new Type[0]); if (defaultConstructor != null && !defaultConstructor.IsAbstract && !defaultConstructor.IsPrivate) { return true; } @@ -735,20 +728,20 @@ namespace Orchard.Logging { /// The method must take a single parameter. /// /// - private MethodInfo FindMethodInfo(Type targetType, string name) { - string requiredMethodNameA = name; - string requiredMethodNameB = "Add" + name; + private static MethodInfo FindMethodInfo(Type targetType, string name) { + var requiredMethodNameA = name; + var requiredMethodNameB = "Add" + name; - MethodInfo[] methods = targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + var methods = targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - foreach (MethodInfo methInfo in methods) { + foreach (var methInfo in methods) { if (!methInfo.IsStatic) { - if (string.Compare(methInfo.Name, requiredMethodNameA, true, System.Globalization.CultureInfo.InvariantCulture) == 0 || - string.Compare(methInfo.Name, requiredMethodNameB, true, System.Globalization.CultureInfo.InvariantCulture) == 0) { + if (string.Compare(methInfo.Name, requiredMethodNameA, true, CultureInfo.InvariantCulture) == 0 || + string.Compare(methInfo.Name, requiredMethodNameB, true, CultureInfo.InvariantCulture) == 0) { // Found matching method name // Look for version with one arg only - System.Reflection.ParameterInfo[] methParams = methInfo.GetParameters(); + var methParams = methInfo.GetParameters(); if (methParams.Length == 1) { return methInfo; } @@ -773,7 +766,7 @@ namespace Orchard.Logging { // Hack to allow use of Level in property if (typeof(Level) == type) { // Property wants a level - Level levelValue = _hierarchy.LevelMap[value]; + var levelValue = _hierarchy.LevelMap[value]; if (levelValue == null) { LogLog.Error("XmlHierarchyConfigurator: Unknown Level Specified [" + value + "]"); @@ -804,19 +797,17 @@ namespace Orchard.Logging { /// /// protected object CreateObjectFromXml(XmlElement element, Type defaultTargetType, Type typeConstraint) { - Type objectType = null; + Type objectType; // Get the object type - string objectTypeString = element.GetAttribute(TypeAttr); - if (objectTypeString == null || objectTypeString.Length == 0) { + var objectTypeString = element.GetAttribute(TypeAttr); + if (String.IsNullOrEmpty(objectTypeString)) { if (defaultTargetType == null) { LogLog.Error("XmlHierarchyConfigurator: Object type not specified. Cannot create object of type [" + typeConstraint.FullName + "]. Missing Value or Type."); return null; } - else { - // Use the default object type - objectType = defaultTargetType; - } + // Use the default object type + objectType = defaultTargetType; } else { // Read the explicit object type @@ -829,7 +820,7 @@ namespace Orchard.Logging { } } - bool requiresConversion = false; + var requiresConversion = false; // Got the object type. Check that it meets the typeConstraint if (typeConstraint != null) { @@ -851,32 +842,23 @@ namespace Orchard.Logging { createdObject = Activator.CreateInstance(objectType); } catch (Exception createInstanceEx) { - LogLog.Error("XmlHierarchyConfigurator: Failed to construct object of type [" + objectType.FullName + "] Exception: " + createInstanceEx.ToString()); + LogLog.Error("XmlHierarchyConfigurator: Failed to construct object of type [" + objectType.FullName + "] Exception: " + createInstanceEx); } // Set any params on object - foreach (XmlNode currentNode in element.ChildNodes) { - if (currentNode.NodeType == XmlNodeType.Element) { - SetParameter((XmlElement)currentNode, createdObject); - } + foreach (var currentNode in element.ChildNodes.Cast().Where(currentNode => currentNode.NodeType == XmlNodeType.Element)) { + SetParameter((XmlElement)currentNode, createdObject); } // Check if we need to call ActivateOptions - IOptionHandler optionHandler = createdObject as IOptionHandler; + var optionHandler = createdObject as IOptionHandler; if (optionHandler != null) { optionHandler.ActivateOptions(); } // Ok object should be initialized - if (requiresConversion) { - // Convert the object type - return OptionConverter.ConvertTypeTo(createdObject, typeConstraint); - } - else { - // The object is of the correct type - return createdObject; - } + return requiresConversion ? OptionConverter.ConvertTypeTo(createdObject, typeConstraint) : createdObject; } } } From 9e40349aa87e8b3456b56cdf6565328e2c21c268 Mon Sep 17 00:00:00 2001 From: Ian Mercer Date: Sat, 19 Mar 2011 10:02:56 -0700 Subject: [PATCH 07/11] Expanding IUserEventHandler to track many more user events such as logon, logoff, confirmed password, ... --HG-- branch : contributions --- .../Controllers/AccountController.cs | 38 ++++++++++++++++-- .../Orchard.Users/Events/IUserEventHandler.cs | 39 ++++++++++++++++++- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs index 018ffdbbe..b24ba80bd 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs @@ -14,6 +14,8 @@ using Orchard.Users.Services; using Orchard.ContentManagement; using Orchard.Users.Models; using Orchard.UI.Notify; +using Orchard.Users.Events; +using System.Collections.Generic; namespace Orchard.Users.Controllers { [HandleError, Themed] @@ -22,17 +24,19 @@ namespace Orchard.Users.Controllers { private readonly IMembershipService _membershipService; private readonly IUserService _userService; private readonly IOrchardServices _orchardServices; - + private readonly IEnumerable _userEventHandlers; public AccountController( IAuthenticationService authenticationService, IMembershipService membershipService, IUserService userService, - IOrchardServices orchardServices) { + IOrchardServices orchardServices, + IEnumerable userEventHandlers) { _authenticationService = authenticationService; _membershipService = membershipService; _userService = userService; _orchardServices = orchardServices; + _userEventHandlers = userEventHandlers; Logger = NullLogger.Instance; T = NullLocalizer.Instance; } @@ -51,8 +55,14 @@ namespace Orchard.Users.Controllers { } //TODO: (erikpo) Add a setting for whether or not to log access denieds since these can fill up a database pretty fast from bots on a high traffic site + //Suggestion: Could instead use the new AccessDenined IUserEventHandler method and let modules decide if they want to log this event? Logger.Information("Access denied to user #{0} '{1}' on {2}", currentUser.Id, currentUser.UserName, returnUrl); + foreach (var userEventHandler in _userEventHandlers) + { + userEventHandler.AccessDenied(currentUser); + } + return View(); } @@ -75,13 +85,22 @@ namespace Orchard.Users.Controllers { } _authenticationService.SignIn(user, false); + foreach (var userEventHandler in _userEventHandlers) + { + userEventHandler.LoggedIn(user); + } return this.RedirectLocal(returnUrl); } public ActionResult LogOff(string returnUrl) { + IUser wasLoggedInUser = _authenticationService.GetAuthenticatedUser(); _authenticationService.SignOut(); - + if (wasLoggedInUser != null) + foreach (var userEventHandler in _userEventHandlers) + { + userEventHandler.LoggedOut(wasLoggedInUser); + } return this.RedirectLocal(returnUrl); } @@ -116,12 +135,17 @@ namespace Orchard.Users.Controllers { if (ValidateRegistration(userName, email, password, confirmPassword)) { // Attempt to register the user + // No need to report this to IUserEventHandler because _membershipService does that for us var user = _membershipService.CreateUser(new CreateUserParams(userName, password, email, null, null, false)); if (user != null) { if ( user.As().EmailStatus == UserStatus.Pending ) { _userService.SendChallengeEmail(user.As(), nonce => Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new { Area = "Orchard.Users", nonce = nonce }))); + foreach (var userEventHandler in _userEventHandlers) + { + userEventHandler.SentChallengeEmail(user); + } return RedirectToAction("ChallengeEmailSent"); } @@ -194,6 +218,10 @@ namespace Orchard.Users.Controllers { if ( validated != null ) { _membershipService.SetPassword(validated, newPassword); + foreach (var userEventHandler in _userEventHandlers) + { + userEventHandler.ChangedPassword(validated); + } return RedirectToAction("ChangePasswordSuccess"); } @@ -265,6 +293,10 @@ namespace Orchard.Users.Controllers { var user = _userService.ValidateChallenge(nonce); if ( user != null ) { + foreach (var userEventHandler in _userEventHandlers) { + userEventHandler.ConfirmedEmail(user); + } + return RedirectToAction("ChallengeEmailSuccess"); } diff --git a/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs index 79b0962ed..f9f8017de 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs @@ -1,7 +1,10 @@ using Orchard.Events; +using Orchard.Security; -namespace Orchard.Users.Events { - public interface IUserEventHandler : IEventHandler { +namespace Orchard.Users.Events +{ + public interface IUserEventHandler : IEventHandler + { /// /// Called before a User is created /// @@ -11,6 +14,38 @@ namespace Orchard.Users.Events { /// Called once a user has been created /// void Created(UserContext context); + + // NEW BELOW HERE + + /// + /// Called once a user has logged in + /// + void LoggedIn(IUser user); + + /// + /// Called when a user explicitly logs out (as opposed to one whos session cookie simply expires) + /// + void LoggedOut(IUser user); + + /// + /// Called when access is denied to a user + /// + void AccessDenied(IUser user); + + /// + /// Called once a user has changed password + /// + void ChangedPassword(IUser user); + + /// + /// Called once a user has confirmed their email address + /// + void SentChallengeEmail(IUser user); + + /// + /// Called once a user has confirmed their email address + /// + void ConfirmedEmail(IUser user); } } From 6140a60b7a1d24ae90584c022ebc6fe5986681bf Mon Sep 17 00:00:00 2001 From: Ian Mercer Date: Sat, 19 Mar 2011 10:28:40 -0700 Subject: [PATCH 08/11] Tweak layout and comments --HG-- branch : contributions --- .../Controllers/AccountController.cs | 15 +++++---------- .../Orchard.Users/Events/IUserEventHandler.cs | 10 +++++----- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs index b24ba80bd..b0cc55829 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs @@ -58,8 +58,7 @@ namespace Orchard.Users.Controllers { //Suggestion: Could instead use the new AccessDenined IUserEventHandler method and let modules decide if they want to log this event? Logger.Information("Access denied to user #{0} '{1}' on {2}", currentUser.Id, currentUser.UserName, returnUrl); - foreach (var userEventHandler in _userEventHandlers) - { + foreach (var userEventHandler in _userEventHandlers) { userEventHandler.AccessDenied(currentUser); } @@ -85,8 +84,7 @@ namespace Orchard.Users.Controllers { } _authenticationService.SignIn(user, false); - foreach (var userEventHandler in _userEventHandlers) - { + foreach (var userEventHandler in _userEventHandlers) { userEventHandler.LoggedIn(user); } @@ -97,8 +95,7 @@ namespace Orchard.Users.Controllers { IUser wasLoggedInUser = _authenticationService.GetAuthenticatedUser(); _authenticationService.SignOut(); if (wasLoggedInUser != null) - foreach (var userEventHandler in _userEventHandlers) - { + foreach (var userEventHandler in _userEventHandlers) { userEventHandler.LoggedOut(wasLoggedInUser); } return this.RedirectLocal(returnUrl); @@ -142,8 +139,7 @@ namespace Orchard.Users.Controllers { if ( user.As().EmailStatus == UserStatus.Pending ) { _userService.SendChallengeEmail(user.As(), nonce => Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new { Area = "Orchard.Users", nonce = nonce }))); - foreach (var userEventHandler in _userEventHandlers) - { + foreach (var userEventHandler in _userEventHandlers) { userEventHandler.SentChallengeEmail(user); } return RedirectToAction("ChallengeEmailSent"); @@ -218,8 +214,7 @@ namespace Orchard.Users.Controllers { if ( validated != null ) { _membershipService.SetPassword(validated, newPassword); - foreach (var userEventHandler in _userEventHandlers) - { + foreach (var userEventHandler in _userEventHandlers) { userEventHandler.ChangedPassword(validated); } return RedirectToAction("ChangePasswordSuccess"); diff --git a/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs index f9f8017de..a58bf5ff7 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs @@ -11,14 +11,14 @@ namespace Orchard.Users.Events void Creating(UserContext context); /// - /// Called once a user has been created + /// Called after a user has been created /// void Created(UserContext context); // NEW BELOW HERE /// - /// Called once a user has logged in + /// Called after a user has logged in /// void LoggedIn(IUser user); @@ -33,17 +33,17 @@ namespace Orchard.Users.Events void AccessDenied(IUser user); /// - /// Called once a user has changed password + /// Called after a user has changed password /// void ChangedPassword(IUser user); /// - /// Called once a user has confirmed their email address + /// Called after a user has confirmed their email address /// void SentChallengeEmail(IUser user); /// - /// Called once a user has confirmed their email address + /// Called after a user has confirmed their email address /// void ConfirmedEmail(IUser user); } From e7cee3a4393fc836c959dcb64ed9311382c6ee3f Mon Sep 17 00:00:00 2001 From: Suha Can Date: Mon, 21 Mar 2011 14:26:56 -0700 Subject: [PATCH 09/11] Fixing bug #17480 (Contribution from alek_sys) --HG-- branch : contributions --- src/Orchard.Web/Core/Shapes/Views/MenuItem.cshtml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Web/Core/Shapes/Views/MenuItem.cshtml b/src/Orchard.Web/Core/Shapes/Views/MenuItem.cshtml index 7b96d871d..5b0d9b766 100644 --- a/src/Orchard.Web/Core/Shapes/Views/MenuItem.cshtml +++ b/src/Orchard.Web/Core/Shapes/Views/MenuItem.cshtml @@ -6,8 +6,10 @@ if (!HasText(Model.Text)) { @DisplayChildren(Model) } else { - if (Model.Href.TrimEnd('/').ToUpperInvariant() == Request.Path.TrimEnd('/').ToUpperInvariant()) { - Model.Classes.Add("current"); + string requestUrl = Request.Path.Replace(Request.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant(); + string modelUrl = Model.Href.Replace(Request.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant(); + if ((!string.IsNullOrEmpty(modelUrl) && requestUrl.StartsWith(modelUrl)) || requestUrl == modelUrl) { + Model.Classes.Add("current"); } var tag = Tag(Model, "li"); @tag.StartElement From 24002d77f5398cd54a12bec3dfb1a756e2acd495 Mon Sep 17 00:00:00 2001 From: Suha Can Date: Mon, 21 Mar 2011 15:14:12 -0700 Subject: [PATCH 10/11] Fixing bug #17506 Deleting Media in Azure throws (Contribution by Travis Pettijohn) --HG-- branch : contributions --- src/Orchard.Azure/AzureFileSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Azure/AzureFileSystem.cs b/src/Orchard.Azure/AzureFileSystem.cs index b8170b117..2e293bef3 100644 --- a/src/Orchard.Azure/AzureFileSystem.cs +++ b/src/Orchard.Azure/AzureFileSystem.cs @@ -223,8 +223,8 @@ namespace Orchard.Azure { EnsurePathIsRelative(path); using ( new HttpContextWeaver() ) { - Container.EnsureBlobExists(path); - var blob = Container.GetBlockBlobReference(String.Concat(_root, path)); + Container.EnsureBlobExists(Combine(_root, path)); + var blob = Container.GetBlockBlobReference(Combine(_root, path)); blob.Delete(); } } From 8eaff3b646ea76357415ec3bc5e7b539586455b2 Mon Sep 17 00:00:00 2001 From: Suha Can Date: Mon, 21 Mar 2011 15:37:20 -0700 Subject: [PATCH 11/11] Cleanup --HG-- branch : contributions --- .../Orchard.Users/Controllers/AccountController.cs | 2 +- .../Modules/Orchard.Users/Events/IUserEventHandler.cs | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs index b0cc55829..945c86768 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs @@ -92,7 +92,7 @@ namespace Orchard.Users.Controllers { } public ActionResult LogOff(string returnUrl) { - IUser wasLoggedInUser = _authenticationService.GetAuthenticatedUser(); + var wasLoggedInUser = _authenticationService.GetAuthenticatedUser(); _authenticationService.SignOut(); if (wasLoggedInUser != null) foreach (var userEventHandler in _userEventHandlers) { diff --git a/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs index a58bf5ff7..d6bbbb634 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs @@ -1,10 +1,8 @@ using Orchard.Events; using Orchard.Security; -namespace Orchard.Users.Events -{ - public interface IUserEventHandler : IEventHandler - { +namespace Orchard.Users.Events { + public interface IUserEventHandler : IEventHandler { /// /// Called before a User is created /// @@ -15,8 +13,6 @@ namespace Orchard.Users.Events /// void Created(UserContext context); - // NEW BELOW HERE - /// /// Called after a user has logged in ///