// Stephen Toub
// stoub@microsoft.com
using System;
using System.Xml;
using System.Collections;
using System.Configuration;
using Msdn.Outlook.Calendaring;
namespace Msdn.Outlook.Calendaring
{
///
/// Configuration section handler for the Outlook Calendar Provider system.
/// Expects a configuration section named "calendarProviders". Under that node
/// is a node "providers". Each "provider" node under "providers" creates
/// a single provider that can be used by the system. If the type of this
/// provider is GroupCalendarProvider, then it can have subproviders as
/// "provider" nodes underneath it, none of which need id attributes.
///
public class CalendarProviderSettings : IConfigurationSectionHandler
{
/// Initialize the section handler.
public CalendarProviderSettings(){}
/// Gets instances of the registered providers from the configuration file.
public static CalendarProvider [] Providers
{
get
{
// 12/26/12: M.Gerow; This statement was commented out because configuration
// section caused error after converting to ASP.NET 3.5, so simply
// hard-coded array of providers below to get things working again.
//return (CalendarProvider[])ConfigurationSettings.GetConfig("outlookCalendar");
CalendarProvider[] providers = new CalendarProvider[4];
providers[0] = new RssCalendarProvider();
providers[0].Initialize("Recent Posts to Blogs on MSDN", new Guid("{5835AD45-BAA7-4766-8E23-C2F870824BAD}"));
providers[0].Configure("http://blogs.msdn.com/MainFeed.aspx");
providers[1] = new EventLogCalendarProvider();
providers[1].Initialize("Application Event Log Calendar", new Guid("{2FC380F2-FD3F-46af-BDB4-40BD727813CE}"));
providers[1].Configure("Application");
providers[2] = new SystemRestoreCalendarProvider();
providers[2].Initialize("System Restore Points", new Guid("{7CB4C0A5-D6EA-48e1-92DE-852148F64149}"));
providers[2].Configure("");
providers[3] = new TaskListCalendarProvider();
providers[3].Initialize("SharePoint 2010 Task List", new Guid("{5996DB53-AE0C-45be-B4C1-86CCBF61B0A7}"));
providers[3].Configure("http://[Your SharePoint Server];[Your Task List Name]");
return providers;
}
}
/// Finds an instance of a registered provider based on its ID.
/// The ID of the calendar provider for which to search.
/// The instance with the matching ID if found; null, otherwise.
public static CalendarProvider Lookup(Guid id)
{
// Loop through each provider to find the one with the specified ID. This is
// fine for a small number of providers as it is an infrequent event and looping
// through a small list is insignificant overhead. If a large number of providers
// is used, it would be better to store Providers as a hashtable, or at least
// as a sorted array.
foreach(CalendarProvider prov in Providers)
{
if (prov.ID.Equals(id)) return prov;
}
// Oops
return null;
}
/// Parses the configuratino section and returns an array of providers.
/// Not used.
/// Not used.
/// The XML configuration section.
/// An array of calendar provider instances based on the providers described in the configuration file.
public object Create(object parent, object configContext, System.Xml.XmlNode section)
{
if (section != null)
{
// Get the providers section
XmlNodeList nodes = section.SelectNodes("providers/provider");
if (nodes != null && nodes.Count > 0)
{
// Add each provider from list
ArrayList providers = new ArrayList(nodes.Count);
ParseProvidersFromList(nodes, providers, true);
return providers.ToArray(typeof(CalendarProvider));
}
}
// No providers, so empty array
return new CalendarProvider[0];
}
/// Parses a list of provider nodes into instances of those providers, adding them to the result list.
/// The provider node to be parsed.
/// The output list of instantiated providers.
///
/// Whether the providers should have IDs. This method is used recursively to parse GroupCalendarProviders. Top-level
/// providers should all have IDs, but providers that are members of a group do not need IDs. It's not an error
/// if they have them, but we ignore them if they do.
///
private void ParseProvidersFromList(XmlNodeList nodes, ArrayList result, bool idRequired)
{
// Add each provider from the list
foreach(XmlNode provNode in nodes)
{
// Get all attributes describing the provider
XmlAttribute typeName = provNode.Attributes["type"];
XmlAttribute name = provNode.Attributes["name"];
XmlAttribute id = provNode.Attributes["id"];
XmlAttribute initData = provNode.Attributes["initData"];
// Make sure we have what we need
if (typeName == null) throw new ConfigurationException("A configured provider is missing a type.", provNode);
if (name == null) throw new ConfigurationException("A configured provider is missing a name.", provNode);
if (idRequired && id == null) throw new ConfigurationException("A configured provider is missing an id.", provNode);
// Instantiate the provider
CalendarProvider provider;
try
{
Type provType = Type.GetType(typeName.Value);
if (!provType.IsSubclassOf(typeof(CalendarProvider))) throw new ConfigurationException("Providers must derive from CalendarProvider.");
provider = (CalendarProvider)Activator.CreateInstance(provType);
}
catch(Exception exc)
{
throw new ConfigurationException("Unable to create provider " + name.Value, exc, provNode);
}
// Initialize the provider with the attribute data. Top-level providers use the provided ID.
// Nested providers have an empty ID.
provider.Initialize(name.Value, idRequired ? new Guid(id.Value) : Guid.Empty);
if (initData != null) provider.Configure(initData.Value);
// If it's a grouping provider, recur. GroupingCalendarProvider allows us to take from a bunch
// of different sources and display on a single calendar to Outlook!! GroupingCalendarProvider can be
// nested, though it's unclear why one would want to do that except for web.config organizational reasons.
// Only top-level providers can be accessed by id currently.
if (provider is GroupingCalendarProvider)
{
ArrayList childProviders = new ArrayList();
ParseProvidersFromList(provNode.SelectNodes("provider"), childProviders, false);
((GroupingCalendarProvider)provider).Providers = (CalendarProvider[])childProviders.ToArray(typeof(CalendarProvider));
}
// Add the provider to the list
result.Add(provider);
}
}
}
}