using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; using SuperSocket.Common; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Config; using SuperSocket.SocketBase.Logging; using SuperSocket.SocketBase.Provider; using SuperSocket.SocketEngine.Configuration; using SuperSocket.SocketBase.Metadata; namespace SuperSocket.SocketEngine { class AppDomainWorkItemFactoryInfoLoader : WorkItemFactoryInfoLoader { public AppDomainWorkItemFactoryInfoLoader(IConfigurationSource config, ILogFactory passedInLogFactory) : base(config, passedInLogFactory) { InitliazeValidationAppDomain(); } public AppDomainWorkItemFactoryInfoLoader(IConfigurationSource config) : base(config) { InitliazeValidationAppDomain(); } private AppDomain m_ValidationAppDomain; private TypeValidator m_Validator; private void InitliazeValidationAppDomain() { m_ValidationAppDomain = AppDomain.CreateDomain("ValidationDomain", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.BaseDirectory, string.Empty, false); var validatorType = typeof(TypeValidator); m_Validator = (TypeValidator)m_ValidationAppDomain.CreateInstanceAndUnwrap(validatorType.Assembly.FullName, validatorType.FullName); } protected override string ValidateProviderType(string typeName) { if (!m_Validator.ValidateTypeName(typeName)) throw new Exception(string.Format("Failed to load type {0}!", typeName)); return typeName; } protected override ServerTypeMetadata GetServerTypeMetadata(string typeName) { return m_Validator.GetServerTypeMetadata(typeName); } public override void Dispose() { if (m_ValidationAppDomain != null) { AppDomain.Unload(m_ValidationAppDomain); m_ValidationAppDomain = null; } base.Dispose(); } } class DefaultBootstrapAppDomainWrap : DefaultBootstrap { private IBootstrap m_Bootstrap; public DefaultBootstrapAppDomainWrap(IBootstrap bootstrap, IConfigurationSource config, string startupConfigFile) : base(config, startupConfigFile) { m_Bootstrap = bootstrap; } protected override IWorkItem CreateWorkItemInstance(string serviceTypeName, StatusInfoAttribute[] serverStatusMetadata) { return new AppDomainAppServer(serviceTypeName, serverStatusMetadata); } internal override bool SetupWorkItemInstance(IWorkItem workItem, WorkItemFactoryInfo factoryInfo) { return workItem.Setup(m_Bootstrap, factoryInfo.Config, factoryInfo.ProviderFactories.ToArray()); } internal override WorkItemFactoryInfoLoader GetWorkItemFactoryInfoLoader(IConfigurationSource config, ILogFactory logFactory) { return new AppDomainWorkItemFactoryInfoLoader(config, logFactory); } } /// /// AppDomainBootstrap /// partial class AppDomainBootstrap : MarshalByRefObject, ILoggerProvider, IBootstrap, IDisposable { private IBootstrap m_InnerBootstrap; /// /// Gets all the app servers running in this bootstrap /// public IEnumerable AppServers { get { return m_InnerBootstrap.AppServers; } } /// /// Gets the config. /// public IRootConfig Config { get { return m_InnerBootstrap.Config; } } /// /// Gets the bootstrap logger. /// ILog ILoggerProvider.Logger { get { var loggerProvider = m_InnerBootstrap as ILoggerProvider; if (loggerProvider == null) return null; return loggerProvider.Logger; } } /// /// Gets the startup config file. /// public string StartupConfigFile { get { return m_InnerBootstrap.StartupConfigFile; } } /// /// Initializes a new instance of the class. /// public AppDomainBootstrap(IConfigurationSource config) { string startupConfigFile = string.Empty; if (config == null) throw new ArgumentNullException("config"); var configSectionSource = config as ConfigurationSection; if (configSectionSource != null) startupConfigFile = configSectionSource.GetConfigSource(); //Keep serializable version of configuration if(!config.GetType().IsSerializable) config = new ConfigurationSource(config); //Still use raw configuration type to bootstrap m_InnerBootstrap = CreateBootstrapWrap(this, config, startupConfigFile); AppDomain.CurrentDomain.SetData("Bootstrap", this); } protected virtual IBootstrap CreateBootstrapWrap(IBootstrap bootstrap, IConfigurationSource config, string startupConfigFile) { return new DefaultBootstrapAppDomainWrap(this, config, startupConfigFile); } /// /// Initializes the bootstrap with the configuration /// /// public bool Initialize() { return m_InnerBootstrap.Initialize(); } /// /// Initializes the bootstrap with the configuration and config resolver. /// /// The server config resolver. /// public bool Initialize(Func serverConfigResolver) { return m_InnerBootstrap.Initialize(serverConfigResolver); } /// /// Initializes the bootstrap with the configuration and config resolver. /// /// The log factory. /// public bool Initialize(ILogFactory logFactory) { return m_InnerBootstrap.Initialize(logFactory); } /// /// Initializes the bootstrap with a listen endpoint replacement dictionary /// /// The listen end point replacement. /// public bool Initialize(IDictionary listenEndPointReplacement) { return m_InnerBootstrap.Initialize(listenEndPointReplacement); } /// /// Initializes the bootstrap with the configuration /// /// The server config resolver. /// The log factory. /// public bool Initialize(Func serverConfigResolver, ILogFactory logFactory) { if (logFactory != null) throw new Exception("You cannot pass in logFactory, if your isolation level is AppDomain!"); return m_InnerBootstrap.Initialize(serverConfigResolver, logFactory); } /// /// Starts this bootstrap. /// /// public StartResult Start() { return m_InnerBootstrap.Start(); } /// /// Stops this bootstrap. /// public void Stop() { m_InnerBootstrap.Stop(); } public string BaseDirectory { get { return m_InnerBootstrap.BaseDirectory; } } void IDisposable.Dispose() { var disposableBootstrap = m_InnerBootstrap as IDisposable; if (disposableBootstrap != null) disposableBootstrap.Dispose(); } } }