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); } } } }