using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Diagnostics;
using System.Xml;
using System.IO;
using System.Collections;
using Microsoft.SharePoint.Utilities;
namespace CKS.FormsBasedAuthentication
{
///
/// Class to create a SharePoint job which updates the layout.sitemap or admin.sitemap
/// for sites which have already been created.
///
/// Typically this call would be used in the FeatureActivated method of SPFeatureReceiver
///
/// (c) 2007 - Vincent Rothwell - http://blog.thekid.me.uk
///
public class UpdateLayoutsSitemap : SPJobDefinition
{
[Persisted]
private System.Collections.Generic.List _entries;
[Persisted]
private string _uniqueID;
[Persisted]
private string _siteUri;
[Persisted]
private bool _adminSite;
private static string _xPath = "//siteMapNode[translate(@url, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = '{0}']";
///
/// Default constructor...used by the system and should not be used directly.
///
public UpdateLayoutsSitemap() { }
///
/// Contructor used to create a stadard instance which modifies the layouts.sitemap.
///
/// The SPWebApplication which needs to be updated
public UpdateLayoutsSitemap(SPWebApplication WebApp)
: this(WebApp, false)
{
}
///
/// Contructor used to create a stadard instance which can modify
/// either the layouts.sitemap or admin.sitemap.
///
/// The SPWebApplication which needs to be updated
/// True to update admin.sitemap False to update layouts.sitemap
public UpdateLayoutsSitemap(SPWebApplication WebApp, bool AdminSite)
: this(WebApp, Guid.NewGuid().ToString(), AdminSite)
{
}
private UpdateLayoutsSitemap(SPWebApplication WebApp, string UniqueID, bool AdminSite)
: base("ULS_" + UniqueID, WebApp, null, SPJobLockType.None)
{
_entries = new List();
_uniqueID = UniqueID;
// ModifiedBySolvion
// bhi - 09.01.2012
// Fixed dispose bug
#region original
//_siteUri = WebApp.Sites[0].RootWeb.Url;
#endregion
using (SPSite site = WebApp.Sites[0])
{
_siteUri = site.RootWeb.Url;
}
// EndModifiedBySolvion
_adminSite = AdminSite;
}
///
/// Add a sitemap which has been installed in \Template\Layouts or \Template\Admin
///
/// The filename of the sitemap containing the entries you wish to add
public void AddSitemap(string fileName)
{
string sFolder = (_adminSite) ? "ADMIN" : "LAYOUTS";
string sSitemapPath = SPUtility.GetVersionedGenericSetupPath("Template\\" + sFolder,15) + "\\" + fileName;
XmlDocument oDoc = new XmlDocument();
oDoc.Load(sSitemapPath);
AddSitemap(oDoc);
}
///
/// Add a previously loaded XML document of sitemap entries .
///
/// The xml document containing the sitemap entries.
public void AddSitemap(XmlDocument SiteMapEntries)
{
XmlNodeList oEntries = SiteMapEntries.DocumentElement.SelectNodes("siteMapNode");
foreach (XmlElement oEntry in oEntries)
AddEntry(oEntry, "/");
}
///
/// Add a new entry defined in the XML element
///
/// The XmlElement containing the sitemap entry
/// The parentUrl for this entry
private void AddEntry(XmlElement currentElement, string parentUrl)
{
string sRequiredParameters = currentElement.GetAttribute("requiredParameters");
if (sRequiredParameters == "") sRequiredParameters = null;
if (!string.IsNullOrEmpty(currentElement.GetAttribute("parentUrl"))) parentUrl = currentElement.GetAttribute("parentUrl");
AddEntry(currentElement.GetAttribute("title"), currentElement.GetAttribute("url"), parentUrl, sRequiredParameters);
XmlNodeList oEntries = currentElement.SelectNodes("siteMapNode");
foreach (XmlElement oEntry in oEntries)
AddEntry(oEntry, currentElement.GetAttribute("url"));
}
///
/// Adds an entry which will ventually be added to the sitemap.
///
/// The Title of the entry
/// The URL of the entry
/// The Parent URL of the entry
public void AddEntry(string theTitle, string theUrl, string parentUrl)
{
AddEntry(theTitle, theUrl, parentUrl, null);
}
///
/// Add an entry which will eventually be added to the sitemap
///
/// The Title of the entry
/// The URL of the entry
/// The Parent URL of the entry
/// The parameters required to be added to the URL
public void AddEntry(string theTitle, string theUrl, string parentUrl, string requiredParameters)
{
string[] arEntry = new string[] { theTitle, theUrl, parentUrl, requiredParameters };
_entries.Add(arEntry);
}
///
/// Submits the job and schedules it to run on every server in the Farm.
///
public void SubmitJob()
{
Schedule = new SPOneTimeSchedule(DateTime.Now);
Title = "Update Layouts Sitemap (" + _uniqueID + ")";
Update();
}
///
/// Called by OWSTIMER when the job runs on a server. Overriden from SPJobDefinition.
///
public override void Execute(Guid targetInstanceId)
{
try
{
SPWebApplication o = SPWebApplication.Lookup(new Uri(_siteUri));
foreach (SPUrlZone z in o.IisSettings.Keys)
UpdateIisSite(o.IisSettings[z]);
}
catch (Exception ex)
{
Debug.WriteLine("Failed to update the sitemap");
Debug.WriteLine(ex);
throw;
}
}
///
/// Update the IIS site with the new sitemap entries
///
/// The settings of the IIS application to update
private void UpdateIisSite(SPIisSettings oSettings)
{
string sSiteMapLocation = oSettings.Path + "\\_app_bin\\" + ((_adminSite) ? "admin" : "layouts") + ".sitemap";
XmlDocument oDoc = new XmlDocument();
oDoc.Load(sSiteMapLocation);
foreach (string[] arEntry in _entries)
AddNewNode(oDoc, arEntry);
if (_entries.Count > 0) oDoc.Save(sSiteMapLocation);
}
///
/// Adds the new sitemap node. Checks the entire documentfor the parent using a
/// case insensitive XPath query. Also checks to see if the path already exists
/// and deletes the current entry.
///
/// The sitemap XML document
/// The array describing the new entry
private void AddNewNode(XmlDocument oDoc, string[] arEntry)
{
XmlNode oNode = oDoc.DocumentElement.SelectSingleNode(string.Format(_xPath, arEntry[2].ToLower()));
if (oNode is XmlElement)
{
XmlElement oParent = (XmlElement)oNode;
// Ensure there isn't a duplicate entry
XmlNode oExistingNode = oParent.OwnerDocument.SelectSingleNode("//*[@url='" + arEntry[1] + "']");
if (oExistingNode != null) oExistingNode.ParentNode.RemoveChild(oExistingNode);
XmlElement oNewNode = oParent.OwnerDocument.CreateElement("siteMapNode");
oNewNode.SetAttribute("title", arEntry[0]);
oNewNode.SetAttribute("url", arEntry[1]);
if (arEntry[3] != null) oNewNode.SetAttribute("requiredParameters", arEntry[3]);
oParent.AppendChild(oNewNode);
}
}
}
}