using System; using System.Collections.Generic; using System.Xml; using System.Reflection; using System.Diagnostics; using winsw.Util; using log4net; namespace winsw.Extensions { public class WinSWExtensionManager { public Dictionary Extensions { private set; get; } public ServiceDescriptor ServiceDescriptor { private set; get; } private static readonly ILog Log = LogManager.GetLogger(typeof(WinSWExtensionManager)); public WinSWExtensionManager(ServiceDescriptor serviceDescriptor) { ServiceDescriptor = serviceDescriptor; Extensions = new Dictionary(); } /// /// Starts all extensions /// /// Start failure public void OnStart(IEventWriter logger) { foreach (var ext in Extensions) { ext.Value.OnStart(logger); } } /// /// Stops all extensions /// /// Stop failure public void OnStop(IEventWriter logger) { foreach (var ext in Extensions) { ext.Value.OnStop(logger); } } /// /// Handler, which is being invoked once the child process is started. /// /// Process public void FireOnProcessStarted(System.Diagnostics.Process process) { foreach (var ext in Extensions) { try { ext.Value.OnProcessStarted(process); } catch (ExtensionException ex) { Log.Error("onProcessStarted() handler failed for " + ext.Value.DisplayName, ex); } } } /// /// Handler, which is being invoked once the child process is terminated. /// /// Process public void FireOnProcessTerminated(System.Diagnostics.Process process) { foreach (var ext in Extensions) { try { ext.Value.OnProcessTerminated(process); } catch (ExtensionException ex) { Log.Error("onProcessTerminated() handler failed for " + ext.Value.DisplayName, ex); } } } //TODO: Implement loading of external extensions. Current version supports internal hack #region Extension load management public void LoadExtensions(IEventWriter logger) { var extensionIds = ServiceDescriptor.ExtensionIds; foreach (String extensionId in extensionIds) { LoadExtension(extensionId, logger); } } /// /// Loads extensions from the configuration file /// /// Extension ID /// Logger /// Loading failure private void LoadExtension(string id, IEventWriter logger) { if (Extensions.ContainsKey(id)) { throw new ExtensionException(id, "Extension has been already loaded"); } var extensionsConfig = ServiceDescriptor.ExtensionsConfiguration; XmlElement configNode =(extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='"+id+"'][1]") as XmlElement : null; if (configNode == null) { throw new ExtensionException(id, "Cannot get the configuration entry"); } var descriptor = WinSWExtensionDescriptor.FromXml(configNode); if (descriptor.Enabled) { IWinSWExtension extension = CreateExtensionInstance(descriptor.Id, descriptor.ClassName); extension.Descriptor = descriptor; extension.Configure(ServiceDescriptor, configNode, logger); Extensions.Add(id, extension); logger.LogEvent("Extension loaded: "+id, EventLogEntryType.Information); } else { logger.LogEvent("Extension is disabled: " + id, EventLogEntryType.Warning); } } private IWinSWExtension CreateExtensionInstance(string id, string className) { ActivationContext ac = AppDomain.CurrentDomain.ActivationContext; Assembly assembly = Assembly.GetCallingAssembly(); Object created; try { Type t = Type.GetType(className); if (t == null) { throw new ExtensionException(id, "Class "+className+" does not exist"); } created = Activator.CreateInstance(t); } catch (Exception ex) { throw new ExtensionException(id, "Cannot load the class by name: "+className, ex); } var extension = created as IWinSWExtension; if (extension == null) { throw new ExtensionException(id, "The loaded class is not a WinSW extension: " + className + ". Type is " + created.GetType()); } return extension; } #endregion } }