void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor, string tenant) { // deduce and apply state changes involved var shellState = _stateManager.GetShellState(); foreach (var feature in descriptor.Features) { var featureName = feature.Name; var featureState = shellState.Features.SingleOrDefault(f => f.Name == featureName); if (featureState == null) { featureState = new ShellFeatureState { Name = featureName }; shellState.Features = shellState.Features.Concat(new[] { featureState }); } if (!featureState.IsInstalled) { _stateManager.UpdateInstalledState(featureState, ShellFeatureState.State.Rising); } if (!featureState.IsEnabled) { _stateManager.UpdateEnabledState(featureState, ShellFeatureState.State.Rising); } } foreach (var featureState in shellState.Features) { var featureName = featureState.Name; if (descriptor.Features.Any(f => f.Name == featureName)) { continue; } if (!featureState.IsDisabled) { _stateManager.UpdateEnabledState(featureState, ShellFeatureState.State.Falling); } } FireApplyChangesIfNeeded(); }
public FeatureCommands(IModuleService moduleService, INotifier notifier, IFeatureManager featureManager, ShellDescriptor shellDescriptor) { _moduleService = moduleService; _notifier = notifier; _featureManager = featureManager; _shellDescriptor = shellDescriptor; }
public ShapePlacementParsingStrategy( IExtensionManager extensionManager, ShellDescriptor shellDescriptor, IPlacementFileParser placementFileParser) { _extensionManager = extensionManager; _shellDescriptor = shellDescriptor; _placementFileParser = placementFileParser; }
public ThemeAwareViewEngine( WorkContext workContext, IEnumerable<IViewEngineProvider> viewEngineProviders, IConfiguredEnginesCache configuredEnginesCache, IExtensionManager extensionManager, ShellDescriptor shellDescriptor) { _workContext = workContext; _viewEngineProviders = viewEngineProviders; _configuredEnginesCache = configuredEnginesCache; _extensionManager = extensionManager; _shellDescriptor = shellDescriptor; Logger = NullLogger.Instance; }
public ShellContext CreateDescribedContext(ShellSettings settings, ShellDescriptor shellDescriptor) { Logger.Debug("Creating described context for tenant {0}", settings.Name); var blueprint = _compositionStrategy.Compose(settings, shellDescriptor); var shellScope = _shellContainerFactory.CreateContainer(settings, blueprint); return new ShellContext { Settings = settings, Descriptor = shellDescriptor, Blueprint = blueprint, LifetimeScope = shellScope, Shell = shellScope.Resolve<ICoeveryShell>(), }; }
public string AddTask(ShellSettings shellSettings, ShellDescriptor shellDescriptor, string eventName, Dictionary<string, object> parameters) { var entry = new Entry { ShellSettings = shellSettings, ShellDescriptor = shellDescriptor, MessageName = eventName, EventData = parameters, TaskId = Guid.NewGuid().ToString("n"), ProcessId = Guid.NewGuid().ToString("n"), }; Logger.Information("Adding event {0} to process {1} for shell {2}", eventName, entry.ProcessId, shellSettings.Name); _entries.GetState().Add(entry); return entry.ProcessId; }
public void NormalExecutionReturnsExpectedObjects() { var settings = new ShellSettings { Name = ShellSettings.DefaultName }; var descriptor = new ShellDescriptor { SerialNumber = 6655321 }; var blueprint = new ShellBlueprint(); var shellLifetimeScope = _container.BeginLifetimeScope("shell"); _container.Mock<IShellDescriptorCache>() .Setup(x => x.Fetch(ShellSettings.DefaultName)) .Returns(descriptor); _container.Mock<ICompositionStrategy>() .Setup(x => x.Compose(settings, descriptor)) .Returns(blueprint); _container.Mock<IShellContainerFactory>() .Setup(x => x.CreateContainer(settings, blueprint)) .Returns(shellLifetimeScope); _container.Mock<IShellDescriptorManager>() .Setup(x => x.GetShellDescriptor()) .Returns(descriptor); _container.Mock<IHttpContextAccessor>() .Setup(x => x.Current()) .Returns(default(HttpContextBase)); var factory = _container.Resolve<IShellContextFactory>(); var context = factory.CreateShellContext(settings); Assert.That(context.Settings, Is.SameAs(settings)); Assert.That(context.Descriptor, Is.SameAs(descriptor)); Assert.That(context.Blueprint, Is.SameAs(blueprint)); Assert.That(context.LifetimeScope, Is.SameAs(shellLifetimeScope)); Assert.That(context.Shell, Is.SameAs(shellLifetimeScope.Resolve<ICoeveryShell>())); }
public ShapeTemplateBindingStrategy( IEnumerable<IShapeTemplateHarvester> harvesters, ShellDescriptor shellDescriptor, IExtensionManager extensionManager, ICacheManager cacheManager, IVirtualPathMonitor virtualPathMonitor, IVirtualPathProvider virtualPathProvider, IEnumerable<IShapeTemplateViewEngine> shapeTemplateViewEngines, IParallelCacheContext parallelCacheContext, Work<ILayoutAwareViewEngine> viewEngine, IWorkContextAccessor workContextAccessor) { _harvesters = harvesters; _shellDescriptor = shellDescriptor; _extensionManager = extensionManager; _cacheManager = cacheManager; _virtualPathMonitor = virtualPathMonitor; _virtualPathProvider = virtualPathProvider; _shapeTemplateViewEngines = shapeTemplateViewEngines; _parallelCacheContext = parallelCacheContext; _viewEngine = viewEngine; _workContextAccessor = workContextAccessor; Logger = NullLogger.Instance; }
public void Store(string name, ShellDescriptor descriptor) { if (Disabled) { return; } lock (_synLock) { VerifyCacheFile(); var text = _appDataFolder.ReadFile(DescriptorCacheFileName); bool tenantCacheUpdated = false; var saveWriter = new StringWriter(); var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(text); XmlNode rootNode = xmlDocument.DocumentElement; if (rootNode != null) { foreach (XmlNode tenantNode in rootNode.ChildNodes) { if (String.Equals(tenantNode.Name, name, StringComparison.OrdinalIgnoreCase)) { tenantNode.InnerText = GetCacheTextForShellDescriptor(descriptor); tenantCacheUpdated = true; break; } } if (!tenantCacheUpdated) { XmlElement newTenant = xmlDocument.CreateElement(name); newTenant.InnerText = GetCacheTextForShellDescriptor(descriptor); rootNode.AppendChild(newTenant); } } xmlDocument.Save(saveWriter); _appDataFolder.CreateFile(DescriptorCacheFileName, saveWriter.ToString()); } }
private static ShellDescriptor GetShellDescriptorFromRecord(ShellDescriptorRecord shellDescriptorRecord) { ShellDescriptor descriptor = new ShellDescriptor { SerialNumber = shellDescriptorRecord.SerialNumber }; var descriptorFeatures = new List<ShellFeature>(); foreach (var descriptorFeatureRecord in shellDescriptorRecord.Features) { descriptorFeatures.Add(new ShellFeature { Name = descriptorFeatureRecord.Name }); } descriptor.Features = descriptorFeatures; var descriptorParameters = new List<ShellParameter>(); foreach (var descriptorParameterRecord in shellDescriptorRecord.Parameters) { descriptorParameters.Add( new ShellParameter { Component = descriptorParameterRecord.Component, Name = descriptorParameterRecord.Name, Value = descriptorParameterRecord.Value }); } descriptor.Parameters = descriptorParameters; return descriptor; }
private void FireApplyChangesIfNeeded() { var shellState = _stateManager.GetShellState(); if (shellState.Features.Any(FeatureIsChanging)) { var descriptor = new ShellDescriptor { Features = shellState.Features .Where(FeatureShouldBeLoadedForStateChangeNotifications) .Select(x => new ShellFeature { Name = x.Name }) .ToArray() }; Logger.Information("Adding pending task 'ApplyChanges' for shell '{0}'", _settings.Name); _processingEngine.AddTask( _settings, descriptor, "IShellStateManagerEventHandler.ApplyChanges", new Dictionary<string, object>()); } }
private static string GetCacheTextForShellDescriptor(ShellDescriptor descriptor) { var sb = new StringBuilder(); sb.Append(descriptor.SerialNumber + "|"); foreach (var feature in descriptor.Features) { sb.Append(feature.Name + ";"); } sb.Append("|"); foreach (var parameter in descriptor.Parameters) { sb.Append(parameter.Component + "," + parameter.Name + "," + parameter.Value); sb.Append(";"); } return sb.ToString(); }
private static ShellDescriptor GetShellDecriptorForCacheText(string p) { string[] fields = p.Trim().Split(new[] { "|" }, StringSplitOptions.None); var shellDescriptor = new ShellDescriptor {SerialNumber = Convert.ToInt32(fields[0])}; string[] features = fields[1].Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries); shellDescriptor.Features = features.Select(feature => new ShellFeature { Name = feature }).ToList(); string[] parameters = fields[2].Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries); shellDescriptor.Parameters = parameters.Select(parameter => parameter.Split(new[] { "," }, StringSplitOptions.None)).Select(parameterFields => new ShellParameter { Component = parameterFields[0], Name = parameterFields[1], Value = parameterFields[2] }).ToList(); return shellDescriptor; }
public static IEnumerable<FeatureDescriptor> EnabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor) { return extensionManager.AvailableFeatures().Where(fd => descriptor.Features.Any(sf => sf.Name == fd.Id)); }
public ShellContext CreateSetupContext(ShellSettings settings) { Logger.Debug("No shell settings available. Creating shell context for setup"); var descriptor = new ShellDescriptor { SerialNumber = -1, Features = new[] { new ShellFeature { Name = "Coevery.Setup" }, new ShellFeature { Name = "Shapes" }, new ShellFeature { Name = "Coevery.jQuery" }, }, }; var blueprint = _compositionStrategy.Compose(settings, descriptor); var shellScope = _shellContainerFactory.CreateContainer(settings, blueprint); return new ShellContext { Settings = settings, Descriptor = descriptor, Blueprint = blueprint, LifetimeScope = shellScope, Shell = shellScope.Resolve<ICoeveryShell>(), }; }
protected StaticFileBindingStrategy(IExtensionManager extensionManager, ShellDescriptor shellDescriptor, IVirtualPathProvider virtualPathProvider) { _extensionManager = extensionManager; _shellDescriptor = shellDescriptor; _virtualPathProvider = virtualPathProvider; }
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor, string tenant) { //TouchFile(); }
public StylesheetBindingStrategy(IExtensionManager extensionManager, ShellDescriptor shellDescriptor, IVirtualPathProvider virtualPathProvider) : base(extensionManager, shellDescriptor, virtualPathProvider) { }
public string Setup(SetupContext context) { string executionId; // The vanilla Coevery distibution has the following features enabled. string[] hardcoded = { // Framework "Coevery.Framework", // Core "Settings", // Modules "Coevery.Recipes", "Coevery.Users" }; context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty<string>()).Distinct().ToList(); var shellSettings = new ShellSettings(_shellSettings); if (string.IsNullOrEmpty(shellSettings.DataProvider)) { shellSettings.DataProvider = context.DatabaseProvider; shellSettings.DataConnectionString = context.DatabaseConnectionString; shellSettings.DataTablePrefix = context.DatabaseTablePrefix; } #region Encryption Settings shellSettings.EncryptionAlgorithm = "AES"; // randomly generated key shellSettings.EncryptionKey = SymmetricAlgorithm.Create(shellSettings.EncryptionAlgorithm).Key.ToHexString(); shellSettings.HashAlgorithm = "HMACSHA256"; // randomly generated key shellSettings.HashKey = HMAC.Create(shellSettings.HashAlgorithm).Key.ToHexString(); #endregion var shellDescriptor = new ShellDescriptor { Features = context.EnabledFeatures.Select(name => new ShellFeature { Name = name }) }; var shellBlueprint = _compositionStrategy.Compose(shellSettings, shellDescriptor); var f = shellBlueprint.Dependencies.Where(d => d.Type == typeof(RecipeManager)).ToList(); // initialize database explicitly, and store shell descriptor using (var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint)) { using (var environment = bootstrapLifetimeScope.CreateWorkContextScope()) { // check if the database is already created (in case an exception occured in the second phase) var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>()); try { var tablePrefix = String.IsNullOrEmpty(shellSettings.DataTablePrefix) ? "" : shellSettings.DataTablePrefix + "_"; schemaBuilder.ExecuteSql("SELECT * FROM " + tablePrefix + "ShellDescriptorRecord"); } catch { var reportsCoordinator = environment.Resolve<IReportsCoordinator>(); reportsCoordinator.Register("Data Migration", "Setup", "Coevery installation"); schemaBuilder.CreateTable("DataMigrationRecord", table => table .Column<int>("Id", column => column.PrimaryKey().Identity()) .Column<string>("DataMigrationClass") .Column<int>("Version")); var dataMigrationManager = environment.Resolve<IDataMigrationManager>(); dataMigrationManager.Update("Settings"); foreach (var feature in context.EnabledFeatures) { dataMigrationManager.Update(feature); } environment.Resolve<IShellDescriptorManager>().UpdateShellDescriptor( 0, shellDescriptor.Features, shellDescriptor.Parameters); } } } // in effect "pump messages" see PostMessage circa 1980 while ( _processingEngine.AreTasksPending() ) _processingEngine.ExecuteNextTask(); // creating a standalone environment. // in theory this environment can be used to resolve any normal components by interface, and those // components will exist entirely in isolation - no crossover between the safemode container currently in effect // must mark state as Running - otherwise standalone enviro is created "for setup" shellSettings.State = TenantState.Running; using (var environment = _coeveryHost.CreateStandaloneEnvironment(shellSettings)) { try { executionId = CreateTenantData(context, environment); } catch { environment.Resolve<ITransactionManager>().Cancel(); throw; } } _shellSettingsManager.SaveSettings(shellSettings); return executionId; }
/// <summary> /// Generates SchemaCommand instances in order to create the schema for a specific feature /// </summary> public IEnumerable<SchemaCommand> GetCreateFeatureCommands(string feature, bool drop) { var dependencies = _extensionManager.AvailableFeatures() .Where(f => String.Equals(f.Id, feature, StringComparison.OrdinalIgnoreCase)) .Where(f => f.Dependencies != null) .SelectMany(f => f.Dependencies) .ToList(); var shellDescriptor = new ShellDescriptor { Features = dependencies.Select(id => new ShellFeature { Name = id }).Union(new[] { new ShellFeature { Name = feature }, new ShellFeature { Name = "Coevery.Framework" } }) }; var shellBlueprint = _compositionStrategy.Compose(_shellSettings, shellDescriptor); if ( !shellBlueprint.Records.Any() ) { yield break; } //var features = dependencies.Select(name => new ShellFeature {Name = name}).Union(new[] {new ShellFeature {Name = feature}, new ShellFeature {Name = "Coevery.Framework"}}); var parameters = _sessionFactoryHolder.GetSessionFactoryParameters(); parameters.RecordDescriptors = shellBlueprint.Records.ToList(); var configuration = _dataServicesProviderFactory .CreateProvider(parameters) .BuildConfiguration(parameters); Dialect.GetDialect(configuration.Properties); var mapping = configuration.BuildMapping(); // get the table mappings using reflection var tablesField = typeof(Configuration).GetField("tables", BindingFlags.Instance | BindingFlags.NonPublic); var tables = ((IDictionary<string, Table>) tablesField.GetValue(configuration)).Values; string prefix = feature.Replace(".", "_") + "_"; foreach(var table in tables.Where(t => parameters.RecordDescriptors.Any(rd => rd.Feature.Descriptor.Id == feature && rd.TableName == t.Name))) { string tableName = table.Name; var recordType = parameters.RecordDescriptors.First(rd => rd.Feature.Descriptor.Id == feature && rd.TableName == tableName).Type; var isContentPart = typeof(ContentPartRecord).IsAssignableFrom(recordType); if ( tableName.StartsWith(prefix) ) { tableName = tableName.Substring(prefix.Length); } if(drop) { yield return new DropTableCommand(tableName); } var command = new CreateTableCommand(tableName); foreach (var column in table.ColumnIterator) { // create copies for local variables to be evaluated at the time the loop is called, and not lately when the la;bda is executed var tableCopy = table; var columnCopy = column; var sqlType = columnCopy.GetSqlTypeCode(mapping); command.Column(column.Name, sqlType.DbType, action => { if (tableCopy.PrimaryKey.Columns.Any(c => c.Name == columnCopy.Name)) { action.PrimaryKey(); if ( !isContentPart ) { action.Identity(); } } if ( columnCopy.IsLengthDefined() && new[] { DbType.StringFixedLength, DbType.String, DbType.AnsiString, DbType.AnsiStringFixedLength }.Contains(sqlType.DbType) && columnCopy.Length != Column.DefaultLength) { action.WithLength(columnCopy.Length); } if (columnCopy.IsPrecisionDefined()) { action.WithPrecision((byte) columnCopy.Precision); action.WithScale((byte) columnCopy.Scale); } if (columnCopy.IsNullable) { action.Nullable(); } if ( columnCopy.IsUnique ) { action.Unique(); } if(columnCopy.DefaultValue != null) { action.WithDefault(columnCopy.DefaultValue); } }); } yield return command; } }
/// <summary> /// A feature is enabled/disabled, the tenant needs to be restarted /// </summary> void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor, string tenant) { if (_shellContexts == null) { return; } Logger.Debug("Shell changed: " + tenant); var context = _shellContexts.FirstOrDefault(x => x.Settings.Name == tenant); if (context == null) { return; } // don't restart when tenant is in setup if (context.Settings.State != TenantState.Running) { return; } // don't flag the tenant if already listed if (_tenantsToRestart.GetState().Any(x => x.Name == tenant)) { return; } Logger.Debug("Adding tenant to restart: " + tenant); _tenantsToRestart.GetState().Add(context.Settings); }