/// <summary> /// Starts the security subsystem using the passed configuration. /// Call this method only once in your application's startup sequence. /// The method prepares and memorizes the main components for /// creating SecurityContext instances in a fastest possible way. /// The main components are global objects: /// ISecurityDataProvider instance, IMessageProvider instance and SecurityCache instance. /// </summary> protected static void StartTheSystem(SecurityConfiguration configuration) { _generalContext = null; // The messageprovider provider must receive ongoing activities at this time. StartedAt = DateTime.UtcNow; int lastActivityIdFromDb; var uncompleted = DataHandler.LoadCompletionState(configuration.SecurityDataProvider, out lastActivityIdFromDb); _messageProvider = configuration.MessageProvider; _messageProvider.MessageReceived += MessageProvider_MessageReceived; Configuration.Identities.SystemUserId = configuration.SystemUserId ?? -1; Configuration.Identities.VisitorUserId = configuration.VisitorUserId ?? 6; Configuration.Identities.EveryoneGroupId = configuration.EveryoneGroupId ?? 8; Configuration.Identities.OwnerGroupId = configuration.OwnerGroupId ?? 9; Configuration.Messaging.CommunicationMonitorRunningPeriodInSeconds = configuration.CommunicationMonitorRunningPeriodInSeconds ?? 30; Configuration.Messaging.SecuritActivityLifetimeInMinutes = configuration.SecuritActivityLifetimeInMinutes ?? 42; Configuration.Messaging.SecuritActivityTimeoutInSeconds = configuration.SecuritActivityTimeoutInSeconds ?? 120; _securityDataProviderPrototype = configuration.SecurityDataProvider; PermissionTypeBase.InferForcedRelations(); using (var op = SnTrace.Security.StartOperation("Security initial loading.")) { _cacheHolder = SecurityCache.Initialize(configuration.SecurityDataProvider); op.Successful = true; } CommunicationMonitor.Initialize(); _generalContext = new SecurityContext(SystemUser); SecurityActivityQueue.Startup(uncompleted, lastActivityIdFromDb); _killed = false; }
public void Start() { GeneralSecurityContext = null; // The message provider must receive ongoing activities at this time. StartedAt = DateTime.UtcNow; var uncompleted = DataHandler.LoadCompletionState(out var lastActivityIdFromDb); PermissionTypeBase.InferForcedRelations(); using (var op = SnTrace.Security.StartOperation("Security initial loading.")) { var cache = new SecurityCache(DataHandler); cache.Initialize(); Cache = cache; op.Successful = true; } EntityManager = new SecurityEntityManager(Cache, DataHandler, MissingEntityHandler); Cache.EntityManager = EntityManager; // Property injection DataHandler.EntityManager = EntityManager; // Property injection PermissionQuery = new PermissionQuery(EntityManager, Cache); CommunicationMonitor = new CommunicationMonitor(DataHandler, Options.Create(MessagingOptions)); GeneralSecurityContext = new SecurityContext(SystemUser, this); SecurityActivityQueue = new SecurityActivityQueue(this, CommunicationMonitor, DataHandler, ActivityHistory); SecurityActivityQueue.Startup(uncompleted, lastActivityIdFromDb); ActivityHistory.SecurityActivityQueue = SecurityActivityQueue; // Property injection MessageProvider.MessageReceived += MessageProvider_MessageReceived; MessageProvider.Initialize(); MessageProvider.Start(StartedAt); _killed = false; }
public void EF_LoadActivities_SmartGapResolution() { int lastActivityIdFromDb; CompletionState uncompleted; var sb = new StringBuilder(); context = Start(); CommunicationMonitor.Stop(); var sctx = context.Security; var user1Id = TestUser.User1.Id; var rootEntityId = Id("E01"); // create some activities with gap sctx.CreateSecurityEntity(rootEntityId, default(int), user1Id); for (int entityId = rootEntityId + 1; entityId < rootEntityId + 11; entityId++) { sctx.CreateSecurityEntity(entityId, rootEntityId, user1Id); Db().ExecuteTestScript(@" -- 2 gap INSERT INTO EFMessages ([SavedBy], [SavedAt], [ExecutionState]) VALUES ('asdf1', GETDATE(),'Wait') INSERT INTO EFMessages ([SavedBy], [SavedAt], [ExecutionState]) VALUES ('qwer1', GETDATE(),'Wait') DELETE EFMessages WHERE Id in (select top 2 Id from [EFMessages] order by Id desc)"); } // these are be unprocessed Db().ExecuteTestScript("UPDATE EFMessages set ExecutionState = 'Wait', LockedBy = null, LockedAt = null"); sb.Clear(); uncompleted = DataHandler.LoadCompletionState(SecurityContext.General.DataProvider, out lastActivityIdFromDb); SecurityActivityQueue.Startup(uncompleted, lastActivityIdFromDb); var cs1 = SecurityActivityQueue.GetCurrentCompletionState(); // expectation: there is no any gap. Assert.AreEqual(0, cs1.Gaps.Length); // create a gap Db().ExecuteTestScript(@" -- 2 gap INSERT INTO EFMessages ([SavedBy], [SavedAt], [ExecutionState]) VALUES ('asdf1', GETDATE(),'Wait') INSERT INTO EFMessages ([SavedBy], [SavedAt], [ExecutionState]) VALUES ('qwer1', GETDATE(),'Wait') DELETE EFMessages WHERE Id in (select top 2 Id from [EFMessages] order by Id desc) -- copy last INSERT INTO EFMessages([SavedBy],[SavedAt],[ExecutionState],[LockedBy],[LockedAt],[Body]) SELECT TOP 1 [SavedBy],GETDATE(),[ExecutionState],[LockedBy],[LockedAt],[Body] FROM EFMessages ORDER BY Id DESC -- 2 gap INSERT INTO EFMessages ([SavedBy], [SavedAt], [ExecutionState]) VALUES ('asdf2', GETDATE(),'Wait') INSERT INTO EFMessages ([SavedBy], [SavedAt], [ExecutionState]) VALUES ('qwer2', GETDATE(),'Wait') DELETE EFMessages WHERE Id in (select top 2 Id from [EFMessages] order by Id desc)"); // last activity sctx.CreateSecurityEntity(101, rootEntityId, user1Id); var cs2 = SecurityActivityQueue.GetCurrentCompletionState(); Assert.AreEqual(4, cs2.Gaps.Length); Assert.AreEqual(cs1.LastActivityId + 6, cs2.LastActivityId); SecurityActivityQueue.HealthCheck(); var cs3 = SecurityActivityQueue.GetCurrentCompletionState(); Assert.AreEqual(0, cs3.Gaps.Length); Assert.AreEqual(cs2.LastActivityId, cs3.LastActivityId); CommunicationMonitor.Start(); }
public void EF_LoadActivities_AtStart_ActivityQueueLevel() { int lastActivityIdFromDb; CompletionState uncompleted; context = Start(); var sctx = context.Security; var user1Id = TestUser.User1.Id; var rootEntityId = Id("E01"); // create 30 activities sctx.CreateSecurityEntity(rootEntityId, default(int), user1Id); for (int entityId = rootEntityId + 1; entityId < rootEntityId + 31; entityId++) { sctx.CreateSecurityEntity(entityId, rootEntityId, user1Id); } var lastId = Db().ExecuteTestScript <int>("select top 1 Id from [EFMessages] order by Id desc").First(); // test0: initial state var expectedCs = new CompletionState { LastActivityId = lastId }; uncompleted = DataHandler.LoadCompletionState(SecurityContext.General.DataProvider, out lastActivityIdFromDb); SecurityActivityQueue.Startup(uncompleted, lastActivityIdFromDb); var cs0 = SecurityActivityQueue.GetCurrentState().Termination; Assert.AreEqual(expectedCs.ToString(), cs0.ToString()); // test1: create some unprocessed activities: 4 continuous activity (except last) + 2 gaps before // last-2 and last-6 "Wait", the others "Executing" by another appdomain. Db().ExecuteTestScript(@"declare @last int select top 1 @last = Id from [EFMessages] order by Id desc UPDATE EFMessages set ExecutionState = 'Executing', LockedBy = 'AnotherComputer' where Id in (@last-1, @last-3, @last-4, @last-9) UPDATE EFMessages set ExecutionState = 'Wait', LockedBy = null, LockedAt = null where Id in (@last-2, @last-6) "); var expectedIsFromDb1 = String.Join(", ", new[] { lastId - 9, lastId - 4, lastId - 3, lastId - 1, lastId }); uncompleted = DataHandler.LoadCompletionState(SecurityContext.General.DataProvider, out lastActivityIdFromDb); SecurityActivityQueue.Startup(uncompleted, lastActivityIdFromDb); var cs1 = SecurityActivityQueue.GetCurrentState().Termination; var idsFromDb1 = String.Join(", ", Db().GetUnprocessedActivityIds()); Assert.AreEqual(expectedCs.ToString(), cs1.ToString()); Assert.AreEqual(expectedIsFromDb1, idsFromDb1); // test2: create unprocessed activities: last 5 continuous activity + 2 gaps before // last-2 and last-6 "Wait", the others "Executing" by another appdomain. Db().ExecuteTestScript(@"declare @last int select top 1 @last = Id from [EFMessages] order by Id desc UPDATE EFMessages set ExecutionState = 'Executing', LockedBy = 'AnotherComputer' where Id in (@last, @last-1, @last-3, @last-4, @last-9) UPDATE EFMessages set ExecutionState = 'Wait', LockedBy = null, LockedAt = null where Id in (@last-2, @last-6) "); var expectedIsFromDb2 = String.Join(", ", new[] { lastId - 9, lastId - 4, lastId - 3, lastId - 1, lastId, lastId }); uncompleted = DataHandler.LoadCompletionState(SecurityContext.General.DataProvider, out lastActivityIdFromDb); SecurityActivityQueue.Startup(uncompleted, lastActivityIdFromDb); var cs2 = SecurityActivityQueue.GetCurrentState().Termination; var idsFromDb2 = String.Join(", ", Db().GetUnprocessedActivityIds()); Assert.AreEqual(expectedCs.ToString(), cs2.ToString()); Assert.AreEqual(expectedIsFromDb2, idsFromDb2); }