// xLibrary, Copyright (C) 2007 Brodrick Bassham.
//
// brodrick.bassham@gmail.com
//
// An ASP.net wrapper for X, a Cross-Browser Javascript Library, Distributed
// under the terms of the GNU LGPL. See http://www.cross-browser.com/ for
// details on X.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
//
using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
namespace xLibrary
{
/// <summary>
/// Loads the requested X functions embedded in this assembly.
/// </summary>
public class xLibraryLoader
{
private readonly string EXTN_XML = ".xml";
private readonly string XPATH_XSYMBOL_ID = "/x_symbol/@id";
private readonly string XPATH_FILE = "/x_symbol/sources/src/file";
private readonly string XPATH_DEP = "/x_symbol/dependencies/dep";
private readonly string FORMAT_RESOURCE = "xLibrary.lib.{0}";
private readonly string ERROR_COMMENT = "// X Function {0} was not found.\n";
private readonly string ERROR_ALERT = "alert('X Function {0} was not found.');\n";
/// <summary>
/// Used to store the dependencies and source for each individual
/// X function.
/// </summary>
private Hashtable xLibraryData;
/// <summary>
/// Creates a new xLibraryLoader used to retrieve the source for each
/// X function.
/// </summary>
public xLibraryLoader()
{
FillHashtable();
}
/// <summary>
/// Runs through all the resources embedded in this assembly and parses
/// the XML files associated with the X functions.
/// </summary>
private void FillHashtable()
{
xLibraryData = new Hashtable();
Assembly asm = Assembly.GetExecutingAssembly();
string[] resources = asm.GetManifestResourceNames();
foreach (string resource in resources)
{
// We are only parsing the XML files for now.
if (String.Compare(Path.GetExtension(resource), EXTN_XML, true) == 0)
{
string id = string.Empty;
string source = string.Empty;
ArrayList dependencyIds = new ArrayList();
// ----------------------------------------
// Load the embedded XML from the resource
// into an XmlDocument object.
//
XmlDocument doc = new XmlDocument();
doc.Load(GetResourceStream(resource));
// ----------------------------------------
// Using XPath, get the x_symbol element's
// id attribute.
//
XmlNode x_symbolId = doc.SelectSingleNode(XPATH_XSYMBOL_ID);
id = x_symbolId.Value;
x_symbolId = null;
// ----------------------------------------
// Using XPath, get the value of the
// "/x_symbol/sources/src/file" element.
//
XmlNode srcFile = doc.SelectSingleNode(XPATH_FILE);
source = GetResource(string.Format(FORMAT_RESOURCE, srcFile.InnerXml));
srcFile = null;
// ----------------------------------------
// Using XPath, get all of the
// "/x_symbol/dependencies/dep" elements.
//
XmlNodeList deps = doc.SelectNodes(XPATH_DEP);
foreach (XmlNode dep in deps)
{
dependencyIds.Add(dep.InnerXml);
}
deps = null;
xFunction function =
new xFunction(id, source, dependencyIds.ToArray(typeof(string)) as string[]);
// Store the xFunction in the Hashtable, indexed by the function name.
xLibraryData.Add(function.Name.ToLower(), function);
}
}
}
/// <summary>
/// Helper method to retrieve the specified resource as a
/// <see cref="T:System.IO.Stream"/>.
/// </summary>
/// <param name="resourceName">
/// The fully qualified path to the embedded resource.
/// </param>
/// <returns>
/// A <see cref="T:System.IO.Stream"/> of the specified resource.
/// </returns>
private Stream GetResourceStream(string resourceName)
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
}
/// <summary>
/// Helper method to retrieve the specified resource as a
/// <see cref="T:System.String"/>.
/// </summary>
/// <param name="resourceName">
/// The fully qualified path to the embedded resource.
/// </param>
/// <returns>
/// The specified resource as a <see cref="T:System.String"/>.
/// </returns>
private string GetResource(string resourceName)
{
return new StreamReader(GetResourceStream(resourceName)).ReadToEnd();
}
/// <summary>
/// Builds the script to output. Keeps track of what functions it has
/// already added, so it does not duplicate them.
/// </summary>
/// <param name="functions">
/// An array of <see cref="T:System.String"/>s containing the names of
/// each of the X Functions to retrieve.
/// </param>
/// <param name="alertOnError">
/// Whether or not to render a javascript alert if we can't find the
/// requested X Function.
/// </param>
/// <returns>
/// A string of all the X Functions requested and their dependencies.
/// </returns>
public string GetScript(string[] functions, bool alertOnError)
{
ArrayList added = new ArrayList();
StringBuilder output = new StringBuilder();
foreach (string function in functions)
{
if (!added.Contains(function))
{
xFunction func = xLibraryData[function.ToLower()] as xFunction;
if (func != null)
{
output.Append(func.Source);
added.Add(func.Name);
output.Append(GetScript(func.Dependencies, alertOnError, added));
}
else
{
output.AppendFormat(ERROR_COMMENT, function);
if (alertOnError)
{
output.AppendFormat(ERROR_ALERT, function);
}
}
}
}
return output.ToString();
}
/// <summary>
/// Builds the script to output recursively. Keeps track of what
/// functions it has already added, so it does not duplicate them.
/// </summary>
/// <param name="functions">
/// An array of <see cref="T:System.String"/>s containing the names of
/// each of the X Functions to retrieve.
/// </param>
/// <param name="alertOnError">
/// Whether or not to render a javascript alert if we can't find the
/// requested X Function.
/// </param>
/// <param name="added">
/// An <see cref="T:System.Collections.ArrayList"/> of function names
/// already added to the output.
/// </param>
/// <returns>
/// A string of all the X Functions requested and their dependencies.
/// </returns>
private string GetScript(string[] functions, bool alertOnError, ArrayList added)
{
StringBuilder output = new StringBuilder();
foreach (string function in functions)
{
if (!added.Contains(function))
{
xFunction func = xLibraryData[function.ToLower()] as xFunction;
if (func != null)
{
output.Append(func.Source);
added.Add(func.Name);
output.Append(GetScript(func.Dependencies, alertOnError, added));
}
else if (alertOnError)
{
output.AppendFormat(ERROR_ALERT, function);
}
}
}
return output.ToString();
}
}
}