blob: 5bc4bd3e1fc3c5f808b87d8b36352d522c97f24a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
namespace Apache.Geode.DUnitFramework
{
public class XmlNodeReaderWriter
{
#region Public accessors, constants and members
public XmlDocument XmlDoc
{
get
{
return m_xmlDoc;
}
}
public const string RootNodeName = "Settings";
#endregion
#region Statics and constants
private static Dictionary<string, XmlNodeReaderWriter> instances = new Dictionary<string, XmlNodeReaderWriter>();
#endregion
#region Private members
private FileStream m_xmlStream = null;
private XmlReader m_xmlReader = null;
private volatile XmlDocument m_xmlDoc = null;
private string m_xmlPath = null;
#endregion
private void Close()
{
if (m_xmlReader != null)
{
m_xmlReader.Close();
m_xmlStream.Close();
}
}
private void ReloadFile(string path)
{
XmlReaderSettings xmlSettings = new XmlReaderSettings();
xmlSettings.IgnoreComments = true;
m_xmlStream = new FileStream(path, FileMode.Open, FileAccess.Read,
FileShare.Read);
m_xmlReader = XmlReader.Create(m_xmlStream, xmlSettings);
m_xmlDoc = new XmlDocument();
m_xmlDoc.Load(m_xmlReader);
m_xmlPath = path;
}
private void Save()
{
if (m_xmlDoc != null)
{
Close();
m_xmlDoc.Save(m_xmlPath);
ReloadFile(m_xmlPath);
}
}
/// <summary>
/// Private constructor to create a ReadConfig instance for the given
/// configuration file.
/// </summary>
/// <param name="path">The path of the XML file to read.</param>
private XmlNodeReaderWriter(string path)
{
try
{
if (!File.Exists(path))
{
FileStream fs = new FileStream(path, FileMode.Create,
FileAccess.Write, FileShare.Read);
if (fs != null)
{
byte[] buffer = Encoding.ASCII.GetBytes(string.Format(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>{0}<{1}>{2}</{3}>{4}",
Environment.NewLine, RootNodeName, Environment.NewLine,
RootNodeName, Environment.NewLine));
fs.Write(buffer, 0, buffer.Length);
fs.Close();
}
else
{
m_xmlDoc = null;
return;
}
}
ReloadFile(path);
}
catch
{
Close();
m_xmlDoc = null;
throw;
}
}
/// <summary>
/// Get an instance of ReadConfig for the given configuration file.
/// </summary>
/// <param name="path">The path of the XML file to read.</param>
/// <returns>An instance of ReadConfig object to be able to read key/value pairs.</returns>
public static XmlNodeReaderWriter GetInstance(string path)
{
XmlNodeReaderWriter instance = null;
if (path != null)
{
lock (((ICollection)instances).SyncRoot)
{
if (instances.ContainsKey(path))
{
instance = instances[path];
}
else
{
instance = new XmlNodeReaderWriter(path);
instances.Add(path, instance);
}
}
}
return instance;
}
/// <summary>
/// Remove an instance from the global table.
/// </summary>
/// <param name="path">The path of the XML file whose instance is to be removed.</param>
public static void RemoveInstance(string path)
{
if (path != null)
{
lock (((ICollection)instances).SyncRoot)
{
if (instances.ContainsKey(path))
{
XmlNodeReaderWriter instance = instances[path];
instance.Close();
instances.Remove(path);
}
}
}
}
public static string GetPathForNode(MethodBase method)
{
return '/' + RootNodeName + '/' + method.ReflectedType.Name +
'/' + method.Name;
}
public static string GetPathForNode(MethodBase method, string nodeName)
{
return GetPathForNode(method.ReflectedType.Name, method.Name, nodeName);
}
public static string GetPathForNode(string typeName)
{
return '/' + RootNodeName + '/' + typeName;
}
public static string GetPathForNode(string typeName, string methodName, string nodeName)
{
return '/' + RootNodeName + '/' + typeName +
'/' + methodName + '/' + nodeName;
}
/// <summary>
/// Select a single XML node having the given xpath.
/// </summary>
/// <param name="xpath">The XPath of the node to search.</param>
/// <returns>The XML node.</returns>
public XmlNode GetNode(string xpath)
{
if (m_xmlDoc != null && xpath != null)
{
lock (m_xmlDoc)
{
return m_xmlDoc.SelectSingleNode(xpath);
}
}
return null;
}
/// <summary>
/// Select the XML nodes having the given xpath.
/// </summary>
/// <param name="xpath">The XPath of the node to search.</param>
/// <returns>The list of XML nodes.</returns>
public XmlNodeList GetNodeList(string xpath)
{
if (m_xmlDoc != null && xpath != null)
{
lock (m_xmlDoc)
{
return m_xmlDoc.SelectNodes(xpath);
}
}
return null;
}
/// <summary>
/// Get the innner text of a node using given xpath.
/// </summary>
/// <param name="xpath">The XPath of the node to search.</param>
/// <returns>The value of the node.</returns>
public string GetValue(string xpath)
{
if (m_xmlDoc != null && xpath != null)
{
lock (m_xmlDoc)
{
XmlNode node = m_xmlDoc.SelectSingleNode(xpath);
if (node != null)
{
return node.InnerText;
}
}
}
return null;
}
/// <summary>
/// Get the given attribute of a node having the given xpath.
/// </summary>
/// <param name="xpath">The XPath of the node to search.</param>
/// <param name="attribName">The name of the attribute to find.</param>
/// <returns>The value of the attribute of the node.</returns>
public string GetAttribute(string xpath, string attribName)
{
if (m_xmlDoc != null && xpath != null)
{
lock (m_xmlDoc)
{
XmlNode node = m_xmlDoc.SelectSingleNode(xpath + "/@" + attribName);
if (node != null)
{
return node.Value;
}
}
}
return null;
}
/// <summary>
/// Get an attribute of a node for the given XmlNode.
/// </summary>
/// <param name="node">The XmlNode to search in.</param>
/// <param name="xpath">The XPath of the node to search.</param>
/// <param name="attribName">The name of the attribute to find.</param>
/// <returns>The value of the attribute of the node.</returns>
public static string GetAttribute(XmlNode node, string attribName)
{
if (node != null)
{
XmlAttribute attrib = node.Attributes[attribName];
if (attrib != null)
{
return attrib.Value;
}
}
return null;
}
/// <summary>
/// Get the attributes for nodes having the given xpath.
/// </summary>
/// <param name="xpath">The XPath of the nodes to search.</param>
/// <returns>
/// List of attributes as key-value pairs for the found nodes.
/// </returns>
public List<Dictionary<string, string>> GetAttributes(string xpath)
{
if (m_xmlDoc != null)
{
lock (m_xmlDoc)
{
return GetAttributes(m_xmlDoc, xpath);
}
}
return null;
}
/// <summary>
/// Get the attributes for nodes having the given xpath for the given XmlNode.
/// </summary>
/// <param name="node">The XmlNode to search in.</param>
/// <param name="xpath">The XPath of the nodes to search.</param>
/// <returns>
/// List of attributes as key-value pairs for the found nodes.
/// </returns>
public static List<Dictionary<string, string>> GetAttributes(
XmlNode node, string xpath)
{
if (xpath != null)
{
XmlNodeList nodeList = node.SelectNodes(xpath);
if (nodeList != null)
{
List<Dictionary<string, string>> valueList = new List<Dictionary<string, string>>();
foreach (XmlNode xmlNode in nodeList)
{
Dictionary<string, string> keyValPairs = new Dictionary<string, string>();
foreach (XmlAttribute xmlAttrib in xmlNode.Attributes)
{
keyValPairs.Add(xmlAttrib.Name, xmlAttrib.Value);
}
valueList.Add(keyValPairs);
}
return valueList;
}
}
return null;
}
#region Convenience functions to get attributes
public static string GetStringValue(XmlNode node, string attribName)
{
return GetStringValue(node, attribName, null);
}
public static string GetStringValue(XmlNode node, string attribName,
string defaultValue)
{
XmlAttribute xmlAttrib = node.Attributes[attribName];
if (xmlAttrib != null && xmlAttrib.Value != null)
{
return xmlAttrib.Value;
}
return defaultValue;
}
public static int String2Int(string str, int defaultValue)
{
try
{
return int.Parse(str);
}
catch
{
return defaultValue;
}
}
/// <summary>
/// Get the number of seconds from the string.
/// </summary>
/// <remarks>
/// If the string contains 'h' or 'm' then it is assumed to be in
/// hours and minutes respectively.
/// </remarks>
/// <param name="str">The string to parse.</param>
/// <param name="defaultValue">
/// The default value to return if string is null or empty.
/// </param>
/// <returns>
/// The number of seconds;
/// <paramref name="defaultValue"/> if string is null of empty.
/// </returns>
public static int String2Seconds(string str, int defaultValue)
{
if (str == null || str.Length == 0)
{
return defaultValue;
}
int totalSecs = 0;
int hPos = str.IndexOf('h');
if (hPos > 0)
{
totalSecs += int.Parse(str.Substring(0, hPos)) * 3600;
str = str.Substring(hPos + 1);
}
int mPos = str.IndexOf('m');
if (mPos > 0)
{
totalSecs += int.Parse(str.Substring(0, mPos)) * 60;
str = str.Substring(mPos + 1);
}
if (str != null && str.Length > 0)
{
str = str.TrimEnd('s');
totalSecs += int.Parse(str);
}
return totalSecs;
}
public static int GetIntValue(XmlNode node, string attribName,
int defaultValue)
{
XmlAttribute xmlAttrib = node.Attributes[attribName];
if (xmlAttrib != null)
{
return String2Int(xmlAttrib.Value, defaultValue);
}
return defaultValue;
}
public static bool String2Bool(string str, bool defaultValue)
{
str = str.ToLower();
if (str == "true" || str == "yes")
{
return true;
}
else if (str == "false" || str == "no")
{
return false;
}
return defaultValue;
}
public static bool GetBoolValue(XmlNode node, string attribName,
bool defaultValue)
{
XmlAttribute xmlAttrib = node.Attributes[attribName];
if (xmlAttrib != null)
{
return String2Bool(xmlAttrib.Value, defaultValue);
}
return defaultValue;
}
#endregion
/// <summary>
/// Get the attributes for a node in the given method.
/// </summary>
/// <param name="method">The method to search the node.</param>
/// <param name="nodeName">The name of the node in the given method.</param>
/// <returns>
/// List of attributes as key-value pairs for the found nodes.
/// </returns>
public List<Dictionary<string, string>> GetValues(MethodBase method, string nodeName)
{
string xpath = GetPathForNode(method, nodeName);
return GetAttributes(xpath);
}
/// <summary>
/// Get the attributes for a node in the given method.
/// </summary>
/// <param name="typeName">The class to which the method belongs.</param>
/// <param name="methodName">The name of the method.</param>
/// <param name="nodeName">The name of the node in the given method.</param>
/// <returns>
/// List of attributes as key-value pairs for the found nodes.
/// </returns>
public List<Dictionary<string, string>> GetValues(string typeName, string methodName, string nodeName)
{
string xpath = '/' + RootNodeName + '/' + typeName +
'/' + methodName + '/' + nodeName;
return GetAttributes(xpath);
}
/// <summary>
/// Convenience method to add a new node with the given path and attributes.
/// All the ancestors of the node that do not exist are also added.
/// Normally should not be used rather XML created manually.
/// </summary>
/// <param name="nodePath">
/// The path of the node to add.
/// This should be a '/' separated path like in XPath.
/// </param>
/// <param name="attributes">
/// Any number of attributes as key value pairs, with a key followed by a value.
/// If they are not even in number then the last value is taken to be empty.
/// </param>
public void AddNodeAttributes(string nodePath, params string[] attributes)
{
if (m_xmlDoc != null && nodePath != null)
{
string[] nodePathSplit = nodePath.Split('/');
string nodePartialPath = string.Empty;
lock (m_xmlDoc)
{
XmlNode currNode = m_xmlDoc;
XmlNode parentNode = m_xmlDoc;
XmlNode newNode;
int i;
for (i = 0; i < nodePathSplit.Length - 1; i++)
{
nodePartialPath += '/' + nodePathSplit[i];
currNode = m_xmlDoc.SelectSingleNode(nodePartialPath);
if (currNode == null)
{
break;
}
parentNode = currNode;
}
for (int j = i; j < nodePathSplit.Length; j++)
{
newNode = m_xmlDoc.CreateElement(nodePathSplit[j]);
parentNode.AppendChild(newNode);
parentNode = newNode;
}
XmlAttribute xmlAttrib;
for (i = 0; i < attributes.Length; i += 2)
{
xmlAttrib = m_xmlDoc.CreateAttribute(attributes[i]);
if ((i + 1) < attributes.Length)
{
xmlAttrib.Value = attributes[i + 1];
}
else
{
xmlAttrib.Value = string.Empty;
}
parentNode.Attributes.Append(xmlAttrib);
}
Save();
}
}
}
/// <summary>
/// Delete the first instance of a node with the given path.
/// </summary>
/// <param name="nodePath">
/// The path of the node to delete.
/// This should be a '/' separated path like in XPath.
/// </param>
public void DeleteNode(string nodePath)
{
if (m_xmlDoc != null && nodePath != null)
{
lock (m_xmlDoc)
{
XmlNode node = m_xmlDoc.SelectSingleNode(nodePath);
if (node != null)
{
node.ParentNode.RemoveChild(node);
Save();
}
}
}
}
/// <summary>
/// Delete all instances of a node with the given path.
/// </summary>
/// <param name="nodePath">
/// The path of the node to delete.
/// This should be a '/' separated path like in XPath.
/// </param>
public void DeleteAllNodes(string nodePath)
{
if (m_xmlDoc != null && nodePath != null)
{
lock (m_xmlDoc)
{
XmlNodeList nodeList = m_xmlDoc.SelectNodes(nodePath);
if (nodeList != null)
{
foreach (XmlNode node in nodeList)
{
node.ParentNode.RemoveChild(node);
}
Save();
}
}
}
}
/// <summary>
/// Set the attributes for the first instance of a node with the given path.
/// If the node is not found then it is added (alongwith all its parents).
/// </summary>
/// <param name="nodePath">
/// The path of the node to modify.
/// This should be a '/' separated path like in XPath.
/// </param>
/// <param name="attributes">
/// The given key value pairs are set as attributes in the first found node.
/// If they are not even in number then the last value is taken to be empty.
/// </param>
public void SetNodeAttributes(string nodePath, params string[] attributes)
{
if (m_xmlDoc != null && nodePath != null)
{
lock (m_xmlDoc)
{
XmlNode xmlNode = m_xmlDoc.SelectSingleNode(nodePath);
if (xmlNode != null)
{
xmlNode.Attributes.RemoveAll();
XmlAttribute xmlAttrib;
for (int i = 0; i < attributes.Length; i += 2)
{
xmlAttrib = m_xmlDoc.CreateAttribute(attributes[i]);
if ((i + 1) < attributes.Length)
{
xmlAttrib.Value = attributes[i + 1];
}
else
{
xmlAttrib.Value = string.Empty;
}
xmlNode.Attributes.Append(xmlAttrib);
}
Save();
}
else
{
AddNodeAttributes(nodePath, attributes);
}
}
}
}
/// <summary>
/// Create a XmlNode from a given XML string.
/// </summary>
/// <param name="xmlString">The XML string for a node.</param>
/// <returns>The XMLNode created from the given string.</returns>
public static XmlNode CreateXmlNode(string xmlString)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
return xmlDoc.FirstChild;
}
}
}