|
From: <mar...@us...> - 2010-02-06 23:11:13
|
Revision: 17
http://cronoscontrol.svn.sourceforge.net/cronoscontrol/?rev=17&view=rev
Author: marioarce
Date: 2010-02-06 23:11:07 +0000 (Sat, 06 Feb 2010)
Log Message:
-----------
Ticket #4
Setting Manager class
Implemented a class that manages an application configuration XML file
Added Paths:
-----------
source/trunk/CronosControl/Libraries/BusinessLogic/Configuration/
source/trunk/CronosControl/Libraries/BusinessLogic/Configuration/Settings/
source/trunk/CronosControl/Libraries/BusinessLogic/Configuration/Settings/SettingManager.cs
Added: source/trunk/CronosControl/Libraries/BusinessLogic/Configuration/Settings/SettingManager.cs
===================================================================
--- source/trunk/CronosControl/Libraries/BusinessLogic/Configuration/Settings/SettingManager.cs (rev 0)
+++ source/trunk/CronosControl/Libraries/BusinessLogic/Configuration/Settings/SettingManager.cs 2010-02-06 23:11:07 UTC (rev 17)
@@ -0,0 +1,575 @@
+//------------------------------------------------------------------------------
+// The contents of this file are subject to the GNU General Public License Version 3.0 ("License"); you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at http://www.cronoscontrol.net/license.html.
+//
+// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+// See the License for the specific language governing rights and limitations under the License.
+//
+// The Original Code is CronosControl.
+// The Initial Developer of the Original Code is WebImageConsulting http://www.wicnow.com/.
+// All Rights Reserved.
+//
+// Contributor(s): Mario Alberto Arce, _______.
+//------------------------------------------------------------------------------
+
+using System;
+using System.IO;
+using System.Xml;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Configuration;
+using System.Collections.Generic;
+
+namespace CronosControl.BusinessLogic.Configuration.Settings
+{
+ /// <summary>
+ /// Setting manager
+ /// Manages an application configuration XML file
+ /// </summary>
+ /// <example>
+ /// <strong>SettingManager.Current["mail/smtpPort"]</strong><br />
+ /// <strong>SettingManager.Current["viewport/width"] = "800"</strong>
+ /// <strong>SettingManager.Current["viewport/background@red_element"] = "F6"</strong>
+ /// </example>
+ /// <remarks>
+ /// Setting values to non-existing nodes in xml configuration file is not supported
+ /// </remarks>
+ /// <seealso href="http://www.w3.org/TR/xpath"/>
+ public partial class SettingManager
+ {
+ #region Constants
+ /// <summary>
+ /// Name of the default configuration file to read if not specified in constructor
+ /// </summary>
+ private const string DEFAULT_CONFIGURATION_FILENAME = "Config.xml";
+
+ /// <summary>
+ /// Name of the default XML element which acts as the configuration root
+ /// </summary>
+ private const string DEFAULT_CONFIG_ROOT = "/configuration";
+
+ /// <summary>
+ /// Indicates a default value to determine if the configuration is cached or not
+ /// </summary>
+ private const bool DEFAULT_IS_CONFIG_CACHEABLE = true;
+
+ /// <summary>
+ /// Indicates a default value to determine if setting values automatically flush the config to disk
+ /// </summary>
+ private const bool DEFAULT_AUTO_FLUSH_ON_SET = true;
+
+ /// <summary>
+ /// Indicates a default value to use in case NULL replacement was set to 'true'
+ /// </summary>
+ private const string DEFAULT_VALUE_IF_NOT_EXISTS = null;
+
+ /// <summary>
+ /// Indicates if non-existent nodes should return a custom value (e.g.: null, "")
+ /// </summary>
+ private const bool DEFAULT_USE_REPLACEMENT_IF_NULL = false;
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingManager"/> class.
+ /// </summary>
+ private SettingManager()
+ : this(null, null)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingManager"/> class.
+ /// </summary>
+ /// <param name="configurationFilePath">The configuration file path.</param>
+ private SettingManager(string configurationFilePath)
+ : this(configurationFilePath, null)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingManager"/> class.
+ /// </summary>
+ /// <param name="configurationFilePath">The configuration file path.</param>
+ /// <param name="rootElement">The root element.</param>
+ private SettingManager(string configurationFilePath, string rootElement)
+ {
+ if (configurationFilePath == null)
+ {
+ // Determines if to use configuration-specified SettingManager fileName, or use default
+ string fileName = DEFAULT_CONFIGURATION_FILENAME;
+ if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["CronosControl.Web.Configuration.FileName"]))
+ {
+ fileName = ConfigurationManager.AppSettings["CronosControl.Web.Configuration.FileName"];
+ }
+
+ // Determines the base dir to construct the full path
+ string baseDir = Thread.GetDomain().BaseDirectory;
+ if (System.Web.HttpContext.Current != null)
+ {
+ try
+ {
+ baseDir = System.Web.HttpContext.Current.Request.PhysicalApplicationPath;
+ }
+ catch
+ {
+ // sometimes during the executing HttpContext.Current.Request would not be initialized,
+ // not even going to be null, but trying to get this value
+ // the application raise an exception, this is reason of this try-catch
+ }
+ }
+ baseDir = baseDir.Replace("/", "\\");
+ configurationFilePath = _ConfigurationFileName = Path.Combine(baseDir, fileName);
+ }
+
+ this._ConfigurationFileName = configurationFilePath;
+
+ if (rootElement == null)
+ {
+ // Determines if to use configuration-specified SettingManager rootElement, or use default
+ if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["CronosControl.Web.Configuration.RootElement"]))
+ {
+ rootElement = ConfigurationManager.AppSettings["CronosControl.Web.Configuration.RootElement"];
+ }
+ else
+ {
+ rootElement = DEFAULT_CONFIG_ROOT;
+ }
+ }
+ this._ConfigurationRoot = rootElement;
+
+ // Determines if configuration is going to be cached in ram, or load it from disk upon each access
+ if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["CronosControl.Web.Configuration.UseCache"]))
+ {
+ _UseCache = ConfigurationManager.AppSettings["CronosControl.Web.Configuration.RootElement"] == "true";
+ }
+ else
+ {
+ _UseCache = DEFAULT_IS_CONFIG_CACHEABLE;
+ }
+ }
+ #endregion
+
+ #region Properties
+ private static SettingManager _Current = null;
+ /// <summary>
+ /// Gets the singleton instance of configuration.
+ /// </summary>
+ /// <value>The current.</value>
+ public static SettingManager Current
+ {
+ get
+ {
+ if (_Current == null)
+ {
+ //NOTE: Not using 'lock' or 'Syncronized' since static variables in .NET now are thread-safe
+ if (_Current == null)
+ {
+ _Current = new SettingManager();
+ }
+ }
+ return _Current;
+ }
+ }
+
+ private bool _UseCache = DEFAULT_IS_CONFIG_CACHEABLE;
+ /// <summary>
+ /// Gets or sets a value indicating whether [use cache].
+ /// </summary>
+ /// <value><c>true</c> if [use cache]; otherwise, <c>false</c>.</value>
+ private bool UseCache
+ {
+ get
+ {
+ return _UseCache;
+ }
+ set
+ {
+ _UseCache = value;
+ }
+ }
+
+ private bool _FlushOnSet = DEFAULT_AUTO_FLUSH_ON_SET;
+ /// <summary>
+ /// Gets or sets a value indicating whether [to flush] when setting values.
+ /// </summary>
+ /// <value><c>true</c> if [flush on set]; otherwise, <c>false</c>.</value>
+ public bool FlushOnSet
+ {
+ get
+ {
+ return _FlushOnSet;
+ }
+ set
+ {
+ _FlushOnSet = value;
+ }
+ }
+
+ private bool _UseValueIfNotExists = DEFAULT_USE_REPLACEMENT_IF_NULL;
+ /// <summary>
+ /// Gets or sets a value indicating whether [use value if not exists], instead of throwing an exception.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if [use value if not exists]; otherwise, <c>false</c>.
+ /// </value>
+ public bool UseValueIfNotExists
+ {
+ get
+ {
+ return _UseValueIfNotExists;
+ }
+ set
+ {
+ _UseValueIfNotExists = value;
+ }
+ }
+
+ private string _ValueIfNotExists = DEFAULT_VALUE_IF_NOT_EXISTS;
+ /// <summary>
+ /// Gets or sets the value that is used if <strong>UseValueIfNotExists</strong> is [true] and a non-existent node was found
+ /// </summary>
+ /// <value>The value if not exists.</value>
+ public string ValueIfNotExists
+ {
+ get
+ {
+ return _ValueIfNotExists;
+ }
+ set
+ {
+ _ValueIfNotExists = value;
+ }
+ }
+
+ private XmlDocument _ConfigurationDocument = null;
+ /// <summary>
+ /// Gets the configuration document.
+ /// </summary>
+ /// <value>The configuration document.</value>
+ private XmlDocument ConfigurationDocument
+ {
+ get
+ {
+ if (_ConfigurationDocument == null)
+ {
+ Reload();
+ }
+ return _ConfigurationDocument;
+ }
+ }
+
+ private string _ConfigurationRoot;
+ /// <summary>
+ /// Gets the configuration root.
+ /// </summary>
+ /// <value>The configuration root.</value>
+ private string ConfigurationRoot
+ {
+ get
+ {
+ if (String.IsNullOrEmpty(_ConfigurationRoot))
+ {
+ _ConfigurationRoot = DEFAULT_CONFIG_ROOT;
+ }
+ return _ConfigurationRoot;
+ }
+ }
+
+ private string _ConfigurationFileName = null;
+ /// <summary>
+ /// Gets the name of the configuration file.
+ /// </summary>
+ /// <value>The name of the configuration file.</value>
+ internal string ConfigurationFileName
+ {
+ get
+ {
+ return _ConfigurationFileName;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the <see cref="System.String"/> with the specified branch.
+ /// </summary>
+ /// <value></value>
+ public string this[string branch, string key]
+ {
+ get
+ {
+ return GetValue(branch + "/" + key);
+ }
+ set
+ {
+ SetValue(branch + "/" + key, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the <see cref="System.String"/> with the specified expression.
+ /// </summary>
+ /// <value></value>
+ public string this[string expression]
+ {
+ get
+ {
+ return GetValue(expression);
+ }
+ set
+ {
+ SetValue(expression, value);
+ }
+ }
+ #endregion
+
+ #region Methods
+ /// <summary>
+ /// Gets the configuration for a specific filename
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <returns></returns>
+ public static SettingManager GetConfiguration(string filename)
+ {
+ return new SettingManager(filename);
+ }
+
+ /// <summary>
+ /// Gets the configuration for a specific file and root name
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <param name="rootElement">The root element.</param>
+ /// <returns></returns>
+ public static SettingManager GetConfiguration(string filename, string rootElement)
+ {
+ return new SettingManager(filename, rootElement);
+ }
+
+ /// <summary>
+ /// Gets the configuration from the current file name, but for a particular node
+ /// </summary>
+ /// <param name="rootElement">The root element.</param>
+ /// <returns></returns>
+ public static SettingManager GetConfigurationFromCurrent(string rootElement)
+ {
+ return new SettingManager(Current.ConfigurationFileName, rootElement);
+ }
+
+ /// <summary>
+ /// Reloads configuration
+ /// </summary>
+ public void Reload()
+ {
+ try
+ {
+ _ConfigurationDocument = new XmlDocument();
+ _ConfigurationDocument.Load(ConfigurationFileName);
+ }
+ catch (Exception ex)
+ {
+ throw new SettingManagerException("Unable to load configuration", ex, this);
+ }
+ }
+
+ /// <summary>
+ /// Gets the value.
+ /// </summary>
+ /// <param name="expression">The expression.</param>
+ /// <returns></returns>
+ public string GetValue(string expression)
+ {
+ if (!UseCache)
+ {
+ Reload();
+ }
+
+ XmlNode node = ConfigurationDocument.SelectSingleNode(ConfigurationRoot + "/" + expression);
+ if (node == null)
+ {
+ if (UseValueIfNotExists)
+ {
+ return ValueIfNotExists;
+ }
+
+ throw new SettingManagerException(
+ "Configuration node '" + expression + "' was not found",
+ this
+ );
+ }
+ else if (node is XmlElement)
+ {
+ return node.InnerText;
+ }
+ else if (node is XmlAttribute)
+ {
+ return node.Value;
+ }
+ else
+ {
+ return node.InnerXml;
+ }
+ }
+
+ /// <summary>
+ /// Sets the value.
+ /// </summary>
+ /// <param name="expression">The expression.</param>
+ /// <param name="value">The value.</param>
+ public void SetValue(string expression, string value)
+ {
+ XmlNode selectedNode = ConfigurationDocument.SelectSingleNode(ConfigurationRoot + "/" + expression);
+ if (selectedNode == null)
+ {
+ throw new SettingManagerException("Selected node not found. Setting values on non-existent nodes is not supported yet", this);
+ }
+ else if (selectedNode is XmlElement)
+ {
+ (selectedNode as XmlElement).InnerText = value;
+ }
+ else if (selectedNode is XmlAttribute)
+ {
+ (selectedNode as XmlAttribute).Value = value;
+ }
+ else
+ {
+ throw new SettingManagerException("The type of configuration node specified is not supported", this);
+ }
+
+ if (FlushOnSet)
+ {
+ try
+ {
+ Flush();
+ }
+ catch (Exception ex)
+ {
+ throw new SettingManagerException(
+ "Unable to save changes to disk. Check the configuration file exists and write access is allowed",
+ ex, this
+ );
+ }
+ }
+ }
+
+ /// <summary>
+ /// Flushes current configuration to disk.
+ /// </summary>
+ public void Flush()
+ {
+
+ try
+ {
+ ConfigurationDocument.Save(ConfigurationFileName);
+ }
+ catch (Exception ex)
+ {
+ throw new SettingManagerException(
+ "Unable to save changes to disk. Check the configuration file exists and write access is allowed",
+ ex, this
+ );
+ }
+ }
+
+ /// <summary>
+ /// Gets a value specifying a branch and key name, where the branch is the parent element of the key element
+ /// </summary>
+ /// <param name="branch">The branch.</param>
+ /// <param name="nodeName">Name of the node.</param>
+ /// <returns></returns>
+ [Obsolete(
+ "Use instead" +
+ " 'SettingManager.Current[\"xpathExpression\"]' or " +
+ " 'SettingManager.Current[\"branch\", \"key\"]'", false
+ )]
+ public string GetNodeValue(string branch, string nodeName)
+ {
+ return GetValue(branch + "/" + nodeName);
+ }
+
+ /// <summary>
+ /// Gets the node value.
+ /// </summary>
+ /// <param name="branch">The branch.</param>
+ /// <param name="nodeName">Name of the node.</param>
+ /// <param name="handleException">if set to <c>true</c> [handle exception].</param>
+ /// <returns></returns>
+ [Obsolete(
+ "Use instead" +
+ " 'SettingManager.Current[\"xpathExpression\"]' or " +
+ " 'SettingManager.Current[\"branch\", \"key\"]'", false
+ )]
+ public string GetNodeValue(string branch, string nodeName, bool handleException)
+ {
+ try
+ {
+ return GetValue(branch + "/" + nodeName);
+ }
+ catch (Exception e)
+ {
+ if (handleException)
+ {
+ e.Data.Add("branch", branch);
+ }
+ else
+ {
+ throw new SettingManagerException(
+ "Unable to get configuration value for key '" + nodeName + "'",
+ e, this
+ );
+ }
+ return null;
+ }
+ }
+ #endregion
+ }
+
+ /// <summary>
+ /// Wraps configuration exceptions
+ /// </summary>
+ public class SettingManagerException : ApplicationException
+ {
+ private SettingManager targetConfiguration = null;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingManagerException"/> class.
+ /// </summary>
+ /// <param name="message">The message.</param>
+ public SettingManagerException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingManagerException"/> class.
+ /// </summary>
+ /// <param name="message">The message.</param>
+ /// <param name="ex">The ex.</param>
+ public SettingManagerException(string message, Exception ex)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingManagerException"/> class.
+ /// </summary>
+ /// <param name="message">The message.</param>
+ /// <param name="cfg">The CFG.</param>
+ public SettingManagerException(string message, SettingManager cfg)
+ : base(message)
+ {
+ targetConfiguration = cfg;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SettingManagerException"/> class.
+ /// </summary>
+ /// <param name="message">The message.</param>
+ /// <param name="ex">The exception.</param>
+ /// <param name="configuration">The configuration.</param>
+ public SettingManagerException(string message, Exception ex, SettingManager configuration)
+ : base(message, ex)
+ {
+ targetConfiguration = configuration;
+ }
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|