SEBWIN-219: Changed and simplified implementation of operation mechanism to allow reconfiguration (i.e. repeating operations).

This commit is contained in:
dbuechel 2018-02-01 08:37:12 +01:00
parent 18b8f66300
commit 196836b7eb
32 changed files with 461 additions and 462 deletions

View file

@ -12,7 +12,7 @@ using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Windows;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
namespace SafeExamBrowser.Client
{
@ -61,18 +61,18 @@ namespace SafeExamBrowser.Client
instances.BuildObjectGraph();
var success = instances.StartupController.TryInitializeApplication(instances.StartupOperations);
//var success = instances.StartupController.TryInitializeApplication(instances.StartupOperations);
if (success)
{
MainWindow = instances.Taskbar;
MainWindow.Closing += MainWindow_Closing;
MainWindow.Show();
}
else
{
Shutdown();
}
//if (success)
//{
// MainWindow = instances.Taskbar;
// MainWindow.Closing += MainWindow_Closing;
// MainWindow.Show();
//}
//else
//{
// Shutdown();
//}
}
private void MainWindow_Closing(object sender, CancelEventArgs e)
@ -80,7 +80,7 @@ namespace SafeExamBrowser.Client
var operations = new Queue<IOperation>(instances.StartupOperations.Reverse());
MainWindow.Hide();
instances.ShutdownController.FinalizeApplication(operations);
//instances.ShutdownController.FinalizeApplication(operations);
}
}
}

View file

@ -7,6 +7,7 @@
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
@ -23,7 +24,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private ITaskbar taskbar;
private IUserInterfaceFactory uiFactory;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public BrowserOperation(
@ -53,6 +54,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
taskbar.AddApplication(browserButton);
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
logger.Info("Terminating browser...");

View file

@ -7,6 +7,7 @@
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
@ -18,7 +19,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private ILogger logger;
private IClientController controller;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public ClientControllerOperation(IClientController controller, ILogger logger)
@ -35,6 +36,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
controller.Start();
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
logger.Info("Stopping event handling...");

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
@ -19,7 +19,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private ILogger logger;
private INativeMethods nativeMethods;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public ClipboardOperation(ILogger logger, INativeMethods nativeMethods)
@ -33,6 +33,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
EmptyClipboard();
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
EmptyClipboard();

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring;
@ -21,7 +21,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private ILogger logger;
private ITaskbar taskbar;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public DisplayMonitorOperation(IDisplayMonitor displayMonitor, ILogger logger, ITaskbar taskbar)
@ -41,6 +41,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
displayMonitor.StartMonitoringDisplayChanges();
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
logger.Info("Restoring working area...");

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring;
@ -21,7 +21,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private ILogger logger;
private INativeMethods nativeMethods;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public KeyboardInterceptorOperation(
@ -40,7 +40,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
SplashScreen.UpdateText(TextKey.SplashScreen_StartKeyboardInterception);
nativeMethods.RegisterKeyboardHook(keyboardInterceptor);
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring;
@ -21,7 +21,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private IMouseInterceptor mouseInterceptor;
private INativeMethods nativeMethods;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public MouseInterceptorOperation(
@ -42,6 +42,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
nativeMethods.RegisterMouseHook(mouseInterceptor);
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
logger.Info("Stopping mouse interception...");

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring;
@ -19,7 +19,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private ILogger logger;
private IProcessMonitor processMonitor;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public ProcessMonitorOperation(ILogger logger, IProcessMonitor processMonitor)
@ -41,6 +41,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
// TODO
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
logger.Info("Stopping process monitoring...");

View file

@ -8,6 +8,7 @@
using SafeExamBrowser.Client.Notifications;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
@ -31,7 +32,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private IUserInterfaceFactory uiFactory;
private IText text;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public TaskbarOperation(
@ -82,6 +83,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
}
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
logger.Info("Terminating taskbar...");

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring;
@ -19,7 +19,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private ILogger logger;
private IWindowMonitor windowMonitor;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public WindowMonitorOperation(ILogger logger, IWindowMonitor windowMonitor)
@ -37,6 +37,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
windowMonitor.StartMonitoringWindows();
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
logger.Info("Stopping window monitoring...");

View file

@ -11,6 +11,7 @@ using SafeExamBrowser.Browser;
using SafeExamBrowser.Configuration;
using SafeExamBrowser.Configuration.Settings;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
@ -47,8 +48,8 @@ namespace SafeExamBrowser.Client
private IUserInterfaceFactory uiFactory;
private IWindowMonitor windowMonitor;
internal IShutdownController ShutdownController { get; private set; }
internal IStartupController StartupController { get; private set; }
//internal IShutdownController ShutdownController { get; private set; }
//internal IStartupController StartupController { get; private set; }
internal Queue<IOperation> StartupOperations { get; private set; }
internal Taskbar Taskbar { get; private set; }

View file

@ -6,18 +6,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
using SafeExamBrowser.Contracts.Behaviour.Operations;
namespace SafeExamBrowser.Contracts.Behaviour
{
public interface IRuntimeController : IStartupController
public interface IRuntimeController
{
/// <summary>
/// Reverts any changes performed during the startup or runtime and releases all used resources.
/// Reverts any changes, releases all used resources and terminates the runtime.
/// </summary>
void FinalizeApplication();
void Terminate();
/// <summary>
/// Initializes a new session and starts performing the runtime logic / event handling.
/// Tries to start the runtime. Returns <c>true</c> if successful, otherwise <c>false</c>.
/// </summary>
void StartSession();
bool TryStart(Queue<IOperation> operations);
}
}

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
namespace SafeExamBrowser.Contracts.Behaviour
{
public interface IShutdownController
{
/// <summary>
/// Reverts any changes performed during the startup or runtime and releases all used resources.
/// </summary>
void FinalizeApplication(Queue<IOperation> operations);
}
}

View file

@ -1,21 +0,0 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
namespace SafeExamBrowser.Contracts.Behaviour
{
public interface IStartupController
{
/// <summary>
/// Tries to initialize the application according to the given queue of operations.
/// Returns <c>true</c> if the initialization was successful, <c>false</c> otherwise.
/// </summary>
bool TryInitializeApplication(Queue<IOperation> operations);
}
}

View file

@ -8,14 +8,14 @@
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Contracts.Behaviour
namespace SafeExamBrowser.Contracts.Behaviour.Operations
{
public interface IOperation
{
/// <summary>
/// Determines whether the startup procedure to which this operation belongs should be aborted.
/// Determines whether the procedure to which this operation belongs should be aborted.
/// </summary>
bool AbortStartup { get; }
bool Abort { get; }
/// <summary>
/// The splash screen to be used to show status information to the user.
@ -27,6 +27,11 @@ namespace SafeExamBrowser.Contracts.Behaviour
/// </summary>
void Perform();
/// <summary>
/// Repeats the operation.
/// </summary>
void Repeat();
/// <summary>
/// Reverts all changes which were made when performing the operation.
/// </summary>

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Collections.Generic;
namespace SafeExamBrowser.Contracts.Behaviour.Operations
{
public interface IOperationSequence
{
/// <summary>
/// Tries to perform the given sequence of operations. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise.
/// </summary>
bool TryPerform(Queue<IOperation> operations);
/// <summary>
/// Tries to repeat all operations of this sequence. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise.
/// </summary>
bool TryRepeat();
/// <summary>
/// Tries to revert all operations of this sequence. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise.
/// </summary>
bool TryRevert();
}
}

View file

@ -55,6 +55,7 @@
<ItemGroup>
<Compile Include="Behaviour\IApplicationController.cs" />
<Compile Include="Behaviour\IRuntimeController.cs" />
<Compile Include="Behaviour\Operations\IOperationSequence.cs" />
<Compile Include="Communication\ICommunication.cs" />
<Compile Include="Communication\IClientProxy.cs" />
<Compile Include="Communication\IRuntimeProxy.cs" />
@ -65,7 +66,7 @@
<Compile Include="Configuration\IRuntimeInfo.cs" />
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
<Compile Include="Behaviour\INotificationController.cs" />
<Compile Include="Behaviour\IOperation.cs" />
<Compile Include="Behaviour\Operations\IOperation.cs" />
<Compile Include="Behaviour\IClientController.cs" />
<Compile Include="Configuration\IIconResource.cs" />
<Compile Include="Configuration\IApplicationInfo.cs" />
@ -77,8 +78,6 @@
<Compile Include="Configuration\Settings\IKeyboardSettings.cs" />
<Compile Include="Configuration\Settings\IMouseSettings.cs" />
<Compile Include="Configuration\Settings\ISettings.cs" />
<Compile Include="Behaviour\IShutdownController.cs" />
<Compile Include="Behaviour\IStartupController.cs" />
<Compile Include="Configuration\Settings\ISettingsRepository.cs" />
<Compile Include="Configuration\Settings\ITaskbarSettings.cs" />
<Compile Include="Configuration\Settings\KioskMode.cs" />

View file

@ -10,40 +10,39 @@ using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Core.Behaviour;
using SafeExamBrowser.Core.Behaviour.Operations;
namespace SafeExamBrowser.Core.UnitTests.Behaviour
namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
{
[TestClass]
public class StartupControllerTests
public class OperationSequenceTests
{
private Mock<ILogger> loggerMock;
private Mock<IRuntimeInfo> runtimeInfoMock;
private Mock<ISystemInfo> systemInfoMock;
private Mock<IText> textMock;
private Mock<IUserInterfaceFactory> uiFactoryMock;
private IStartupController sut;
private IOperationSequence sut;
[TestInitialize]
public void Initialize()
{
loggerMock = new Mock<ILogger>();
runtimeInfoMock = new Mock<IRuntimeInfo>();
systemInfoMock = new Mock<ISystemInfo>();
textMock = new Mock<IText>();
uiFactoryMock = new Mock<IUserInterfaceFactory>();
uiFactoryMock.Setup(f => f.CreateSplashScreen(runtimeInfoMock.Object, textMock.Object)).Returns(new Mock<ISplashScreen>().Object);
sut = new StartupController(loggerMock.Object, runtimeInfoMock.Object, systemInfoMock.Object, textMock.Object, uiFactoryMock.Object);
sut = new OperationSequence(loggerMock.Object, runtimeInfoMock.Object, textMock.Object, uiFactoryMock.Object);
}
#region Perform Tests
[TestMethod]
public void MustCorrectlyAbortProcess()
{
@ -52,13 +51,13 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operationB.SetupGet(o => o.AbortStartup).Returns(true);
operationB.SetupGet(o => o.Abort).Returns(true);
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
var result = sut.TryInitializeApplication(operations);
var success = sut.TryPerform(operations);
operationA.Verify(o => o.Perform(), Times.Once);
operationA.Verify(o => o.Revert(), Times.Once);
@ -67,7 +66,7 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
operationC.Verify(o => o.Perform(), Times.Never);
operationC.Verify(o => o.Revert(), Times.Never);
Assert.IsFalse(result);
Assert.IsFalse(success);
}
[TestMethod]
@ -82,7 +81,7 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
var result = sut.TryInitializeApplication(operations);
var success = sut.TryPerform(operations);
operationA.Verify(o => o.Perform(), Times.Once);
operationA.Verify(o => o.Revert(), Times.Never);
@ -91,7 +90,7 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
operationC.Verify(o => o.Perform(), Times.Once);
operationC.Verify(o => o.Revert(), Times.Never);
Assert.IsTrue(result);
Assert.IsTrue(success);
}
[TestMethod]
@ -111,8 +110,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.TryInitializeApplication(operations);
var success = sut.TryPerform(operations);
Assert.IsTrue(success);
Assert.IsTrue(a == 1);
Assert.IsTrue(b == 2);
Assert.IsTrue(c == 3);
@ -134,7 +134,7 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
operations.Enqueue(operationC.Object);
operations.Enqueue(operationD.Object);
var result = sut.TryInitializeApplication(operations);
var success = sut.TryPerform(operations);
operationA.Verify(o => o.Perform(), Times.Once);
operationA.Verify(o => o.Revert(), Times.Once);
@ -145,11 +145,11 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
operationD.Verify(o => o.Perform(), Times.Never);
operationD.Verify(o => o.Revert(), Times.Never);
Assert.IsFalse(result);
Assert.IsFalse(success);
}
[TestMethod]
public void MustRevertOperationsInSequence()
public void MustRevertOperationsInSequenceAfterPerformError()
{
int current = 0, a = 0, b = 0, c = 0, d = 0;
var operationA = new Mock<IOperation>();
@ -169,8 +169,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
operations.Enqueue(operationC.Object);
operations.Enqueue(operationD.Object);
sut.TryInitializeApplication(operations);
var success = sut.TryPerform(operations);
Assert.IsFalse(success);
Assert.IsTrue(d == 0);
Assert.IsTrue(c == 1);
Assert.IsTrue(b == 2);
@ -178,7 +179,7 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
}
[TestMethod]
public void MustContinueToRevertOperationsInCaseOfError()
public void MustContinueToRevertOperationsAfterPerformError()
{
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
@ -194,7 +195,7 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
var result = sut.TryInitializeApplication(operations);
var result = sut.TryPerform(operations);
operationA.Verify(o => o.Perform(), Times.Once);
operationA.Verify(o => o.Revert(), Times.Once);
@ -207,7 +208,7 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
[TestMethod]
public void MustSucceedWithEmptyQueue()
{
var result = sut.TryInitializeApplication(new Queue<IOperation>());
var result = sut.TryPerform(new Queue<IOperation>());
Assert.IsTrue(result);
}
@ -217,7 +218,151 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
public void MustNotFailInCaseOfUnexpectedError()
{
uiFactoryMock.Setup(l => l.CreateSplashScreen(It.IsAny<IRuntimeInfo>(), It.IsAny<IText>())).Throws(new Exception());
sut.TryInitializeApplication(new Queue<IOperation>());
var success = sut.TryPerform(new Queue<IOperation>());
Assert.IsFalse(success);
}
#endregion
#region Repeat Tests
[TestMethod]
public void Fail()
{
// TODO
Assert.Fail();
}
#endregion
#region Revert Tests
[TestMethod]
public void MustRevertOperations()
{
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.TryPerform(operations);
var success = sut.TryRevert();
operationA.Verify(o => o.Revert(), Times.Once);
operationB.Verify(o => o.Revert(), Times.Once);
operationC.Verify(o => o.Revert(), Times.Once);
Assert.IsTrue(success);
}
[TestMethod]
public void MustRevertOperationsInSequence()
{
int current = 0, a = 0, b = 0, c = 0;
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operationA.Setup(o => o.Revert()).Callback(() => a = ++current);
operationB.Setup(o => o.Revert()).Callback(() => b = ++current);
operationC.Setup(o => o.Revert()).Callback(() => c = ++current);
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.TryPerform(operations);
var success = sut.TryRevert();
Assert.IsTrue(success);
Assert.IsTrue(c == 1);
Assert.IsTrue(b == 2);
Assert.IsTrue(a == 3);
}
[TestMethod]
public void MustContinueToRevertOperationsInCaseOfError()
{
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operationA.Setup(o => o.Revert()).Throws<Exception>();
operationB.Setup(o => o.Revert()).Throws<Exception>();
operationC.Setup(o => o.Revert()).Throws<Exception>();
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.TryPerform(operations);
var success = sut.TryRevert();
operationA.Verify(o => o.Revert(), Times.Once);
operationB.Verify(o => o.Revert(), Times.Once);
operationC.Verify(o => o.Revert(), Times.Once);
Assert.IsFalse(success);
}
[TestMethod]
public void MustOnlyRevertPerformedOperations()
{
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operationB.SetupGet(o => o.Abort).Returns(true);
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.TryPerform(operations);
var success = sut.TryRevert();
operationA.Verify(o => o.Revert(), Times.Once);
operationB.Verify(o => o.Revert(), Times.Once);
operationC.Verify(o => o.Revert(), Times.Never);
Assert.IsTrue(success);
}
[TestMethod]
public void MustNotFailWithEmptyQueueWhenReverting()
{
sut.TryPerform(new Queue<IOperation>());
sut.TryRevert();
}
[TestMethod]
public void MustNotFailWithoutPerformWhenReverting()
{
var success = sut.TryRevert();
Assert.IsTrue(success);
}
[TestMethod]
public void MustNotFailInCaseOfUnexpectedErrorWhenReverting()
{
uiFactoryMock.Setup(l => l.CreateSplashScreen(It.IsAny<IRuntimeInfo>(), It.IsAny<IText>())).Throws(new Exception());
sut.TryRevert();
}
#endregion
}
}

View file

@ -1,148 +0,0 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Core.Behaviour;
namespace SafeExamBrowser.Core.UnitTests.Behaviour
{
[TestClass]
public class ShutdownControllerTests
{
private Mock<ILogger> loggerMock;
private Mock<IRuntimeInfo> runtimeInfoMock;
private Mock<IText> textMock;
private Mock<IUserInterfaceFactory> uiFactoryMock;
private IShutdownController sut;
[TestInitialize]
public void Initialize()
{
loggerMock = new Mock<ILogger>();
runtimeInfoMock = new Mock<IRuntimeInfo>();
textMock = new Mock<IText>();
uiFactoryMock = new Mock<IUserInterfaceFactory>();
uiFactoryMock.Setup(f => f.CreateSplashScreen(runtimeInfoMock.Object, textMock.Object)).Returns(new Mock<ISplashScreen>().Object);
sut = new ShutdownController(loggerMock.Object, runtimeInfoMock.Object, textMock.Object, uiFactoryMock.Object);
}
[TestMethod]
public void MustRevertOperations()
{
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.FinalizeApplication(operations);
operationA.Verify(o => o.Revert(), Times.Once);
operationA.Verify(o => o.Perform(), Times.Never);
operationB.Verify(o => o.Revert(), Times.Once);
operationB.Verify(o => o.Perform(), Times.Never);
operationC.Verify(o => o.Revert(), Times.Once);
operationC.Verify(o => o.Perform(), Times.Never);
}
[TestMethod]
public void MustRevertOperationsInSequence()
{
int current = 0, a = 0, b = 0, c = 0;
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operationA.Setup(o => o.Revert()).Callback(() => a = ++current);
operationB.Setup(o => o.Revert()).Callback(() => b = ++current);
operationC.Setup(o => o.Revert()).Callback(() => c = ++current);
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.FinalizeApplication(operations);
Assert.IsTrue(a == 1);
Assert.IsTrue(b == 2);
Assert.IsTrue(c == 3);
}
[TestMethod]
public void MustContinueToRevertOperationsInCaseOfError()
{
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operationA.Setup(o => o.Revert()).Throws<Exception>();
operationB.Setup(o => o.Revert()).Throws<Exception>();
operationC.Setup(o => o.Revert()).Throws<Exception>();
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.FinalizeApplication(operations);
operationA.Verify(o => o.Revert(), Times.Once);
operationB.Verify(o => o.Revert(), Times.Once);
operationC.Verify(o => o.Revert(), Times.Once);
}
[TestMethod]
public void MustNotEvaluateAbortFlag()
{
var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operationB.SetupGet(o => o.AbortStartup).Returns(true);
operations.Enqueue(operationA.Object);
operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object);
sut.FinalizeApplication(operations);
operationA.Verify(o => o.Revert(), Times.Once);
operationB.Verify(o => o.Revert(), Times.Once);
operationC.Verify(o => o.Revert(), Times.Once);
}
[TestMethod]
public void MustNotFailWithEmptyQueue()
{
sut.FinalizeApplication(new Queue<IOperation>());
}
[TestMethod]
public void MustNotFailInCaseOfUnexpectedError()
{
uiFactoryMock.Setup(l => l.CreateSplashScreen(It.IsAny<IRuntimeInfo>(), It.IsAny<IText>())).Throws(new Exception());
sut.FinalizeApplication(new Queue<IOperation>());
}
}
}

View file

@ -79,8 +79,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Behaviour\Operations\I18nOperationTests.cs" />
<Compile Include="Behaviour\StartupControllerTests.cs" />
<Compile Include="Behaviour\ShutdownControllerTests.cs" />
<Compile Include="Behaviour\Operations\OperationSequenceTests.cs" />
<Compile Include="I18n\TextTests.cs" />
<Compile Include="I18n\XmlTextResourceTests.cs" />
<Compile Include="Logging\DefaultLogFormatterTests.cs" />

View file

@ -9,7 +9,7 @@
using System.Globalization;
using System.IO;
using System.Reflection;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
@ -22,7 +22,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
private ILogger logger;
private IText text;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public I18nOperation(ILogger logger, IText text)
@ -42,6 +42,11 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
text.Initialize(textResource);
}
public void Repeat()
{
// Nothing to do here...
}
public void Revert()
{
// Nothing to do here...

View file

@ -9,35 +9,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Core.Behaviour
namespace SafeExamBrowser.Core.Behaviour.Operations
{
public class StartupController : IStartupController
public class OperationSequence : IOperationSequence
{
private ILogger logger;
private IRuntimeInfo runtimeInfo;
private ISplashScreen splashScreen;
private ISystemInfo systemInfo;
private IText text;
private IUserInterfaceFactory uiFactory;
private Stack<IOperation> stack = new Stack<IOperation>();
public StartupController(ILogger logger, IRuntimeInfo runtimeInfo, ISystemInfo systemInfo, IText text, IUserInterfaceFactory uiFactory)
public OperationSequence(ILogger logger, IRuntimeInfo runtimeInfo, IText text, IUserInterfaceFactory uiFactory)
{
this.logger = logger;
this.runtimeInfo = runtimeInfo;
this.systemInfo = systemInfo;
this.text = text;
this.uiFactory = uiFactory;
}
public bool TryInitializeApplication(Queue<IOperation> operations)
public bool TryPerform(Queue<IOperation> operations)
{
var success = false;
@ -50,18 +48,62 @@ namespace SafeExamBrowser.Core.Behaviour
{
RevertOperations();
}
Finish(success);
}
catch (Exception e)
{
LogAndShowException(e);
Finish(false);
logger.Error($"Failed to perform operations!", e);
}
finally
{
Finish();
}
return success;
}
public bool TryRepeat()
{
throw new NotImplementedException();
}
public bool TryRevert()
{
var success = false;
try
{
Initialize();
success = RevertOperations(false);
}
catch (Exception e)
{
logger.Error($"Failed to revert operations!", e);
}
finally
{
Finish();
}
return success;
}
private void Initialize(int? operationCount = null)
{
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
if (operationCount.HasValue)
{
splashScreen.SetMaxProgress(operationCount.Value);
}
else
{
splashScreen.SetIndeterminate();
}
splashScreen.UpdateText(TextKey.SplashScreen_StartupProcedure);
splashScreen.Show();
}
private bool Perform(Queue<IOperation> operations)
{
foreach (var operation in operations)
@ -75,12 +117,12 @@ namespace SafeExamBrowser.Core.Behaviour
}
catch (Exception e)
{
LogAndShowException(e);
logger.Error($"Failed to perform operation '{operation.GetType().Name}'!", e);
return false;
}
if (operation.AbortStartup)
if (operation.Abort)
{
return false;
}
@ -91,8 +133,10 @@ namespace SafeExamBrowser.Core.Behaviour
return true;
}
private void RevertOperations()
private bool RevertOperations(bool regress = true)
{
var success = true;
while (stack.Any())
{
var operation = stack.Pop();
@ -104,41 +148,20 @@ namespace SafeExamBrowser.Core.Behaviour
catch (Exception e)
{
logger.Error($"Failed to revert operation '{operation.GetType().Name}'!", e);
success = false;
}
splashScreen.Regress();
}
}
private void Initialize(int operationCount)
{
logger.Info("--- Initiating startup procedure ---");
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
splashScreen.SetMaxProgress(operationCount);
splashScreen.UpdateText(TextKey.SplashScreen_StartupProcedure);
splashScreen.Show();
}
private void LogAndShowException(Exception e)
{
logger.Error($"Failed to initialize application!", e);
uiFactory.Show(text.Get(TextKey.MessageBox_StartupError), text.Get(TextKey.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error);
logger.Info("Reverting operations...");
}
private void Finish(bool success = true)
{
if (success)
{
logger.Info("--- Application successfully initialized! ---");
logger.Log(string.Empty);
}
else
{
logger.Info("--- Startup procedure aborted! ---");
if (regress)
{
splashScreen.Regress();
}
}
return success;
}
private void Finish()
{
splashScreen?.Close();
}
}

View file

@ -1,98 +0,0 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections.Generic;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Core.Behaviour
{
public class ShutdownController : IShutdownController
{
private ILogger logger;
private IRuntimeInfo runtimeInfo;
private ISplashScreen splashScreen;
private IText text;
private IUserInterfaceFactory uiFactory;
public ShutdownController(ILogger logger, IRuntimeInfo runtimeInfo, IText text, IUserInterfaceFactory uiFactory)
{
this.logger = logger;
this.runtimeInfo = runtimeInfo;
this.text = text;
this.uiFactory = uiFactory;
}
public void FinalizeApplication(Queue<IOperation> operations)
{
try
{
Initialize();
Revert(operations);
Finish();
}
catch (Exception e)
{
LogAndShowException(e);
Finish(false);
}
}
private void Revert(Queue<IOperation> operations)
{
foreach (var operation in operations)
{
operation.SplashScreen = splashScreen;
try
{
operation.Revert();
}
catch (Exception e)
{
logger.Error($"Failed to revert operation '{operation.GetType().Name}'!", e);
}
}
}
private void Initialize()
{
logger.Log(string.Empty);
logger.Info("--- Initiating shutdown procedure ---");
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
splashScreen.SetIndeterminate();
splashScreen.UpdateText(TextKey.SplashScreen_ShutdownProcedure);
splashScreen.Show();
}
private void LogAndShowException(Exception e)
{
logger.Error($"Failed to finalize application!", e);
uiFactory.Show(text.Get(TextKey.MessageBox_ShutdownError), text.Get(TextKey.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error);
}
private void Finish(bool success = true)
{
if (success)
{
logger.Info("--- Application successfully finalized! ---");
}
else
{
logger.Info("--- Shutdown procedure failed! ---");
}
splashScreen?.Close();
}
}
}

View file

@ -56,8 +56,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Behaviour\Operations\I18nOperation.cs" />
<Compile Include="Behaviour\ShutdownController.cs" />
<Compile Include="Behaviour\StartupController.cs" />
<Compile Include="Behaviour\Operations\OperationSequence.cs" />
<Compile Include="Communication\BaseProxy.cs" />
<Compile Include="Communication\Messages\Message.cs" />
<Compile Include="Communication\ServiceProxy.cs" />

View file

@ -166,7 +166,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
sut.Perform();
Assert.IsTrue(sut.AbortStartup);
Assert.IsTrue(sut.Abort);
}
[TestMethod]
@ -181,7 +181,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
sut.Perform();
Assert.IsFalse(sut.AbortStartup);
Assert.IsFalse(sut.Abort);
}
}
}

View file

@ -91,7 +91,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
sut.Perform();
Assert.IsTrue(sut.AbortStartup);
Assert.IsTrue(sut.Abort);
}
[TestMethod]
@ -103,7 +103,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
sut.Perform();
service.VerifySet(s => s.Ignore = true);
Assert.IsFalse(sut.AbortStartup);
Assert.IsFalse(sut.Abort);
}
[TestMethod]

View file

@ -60,13 +60,9 @@ namespace SafeExamBrowser.Runtime
instances.BuildObjectGraph();
instances.LogStartupInformation();
var success = instances.RuntimeController.TryInitializeApplication(instances.StartupOperations);
var success = instances.RuntimeController.TryStart(instances.StartupOperations);
if (success)
{
instances.RuntimeController.StartSession();
}
else
if (!success)
{
Shutdown();
}
@ -74,7 +70,7 @@ namespace SafeExamBrowser.Runtime
protected override void OnExit(ExitEventArgs e)
{
instances.RuntimeController.FinalizeApplication();
instances.RuntimeController.Terminate();
instances.LogShutdownInformation();
base.OnExit(e);

View file

@ -8,7 +8,7 @@
using System;
using System.IO;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
@ -26,7 +26,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
private IUserInterfaceFactory uiFactory;
private string[] commandLineArgs;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public ConfigurationOperation(
@ -60,8 +60,8 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
if (settings.ConfigurationMode == ConfigurationMode.ConfigureClient && UserWantsToAbortStartup())
{
AbortStartup = true;
logger.Info($"The user chose to {(AbortStartup ? "abort" : "continue")} the application startup after successful client configuration.");
Abort = true;
logger.Info($"The user chose to {(Abort ? "abort" : "continue")} the application startup after successful client configuration.");
}
}
else
@ -71,6 +71,11 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
}
}
public void Repeat()
{
// TODO
}
public void Revert()
{
// Nothing to do here...

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
@ -20,7 +20,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
private ISettingsRepository settingsRepository;
private KioskMode kioskMode;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public KioskModeOperation(ILogger logger, ISettingsRepository settingsRepository)
@ -46,6 +46,11 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
}
}
public void Repeat()
{
// TODO
}
public void Revert()
{
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
@ -63,22 +68,22 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
private void CreateNewDesktop()
{
// TODO
}
private void CloseNewDesktop()
{
// TODO
}
private void DisableExplorerShell()
{
// TODO
}
private void RestartExplorerShell()
{
// TODO
}
}
}

View file

@ -7,7 +7,7 @@
*/
using System;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
@ -25,7 +25,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
private ISettingsRepository settingsRepository;
private IText text;
public bool AbortStartup { get; private set; }
public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; }
public ServiceOperation(ILogger logger, IServiceProxy service, ISettingsRepository settingsRepository, IText text)
@ -48,34 +48,26 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
}
catch (Exception e)
{
var message = "Failed to connect to the service component!";
if (serviceMandatory)
{
logger.Error(message, e);
}
else
{
logger.Info($"{message} Reason: {e.Message}");
}
LogException(e);
}
if (serviceMandatory && !serviceAvailable)
{
AbortStartup = true;
Abort = true;
logger.Info("Aborting startup because the service is mandatory but not available!");
}
else if (!serviceAvailable)
{
service.Ignore = true;
logger.Info("All service-related operations will be ignored, since the service is optional and not available.");
}
else
{
logger.Info($"The service is {(serviceMandatory ? "mandatory" : "optional")} and available.");
service.Ignore = !serviceAvailable;
logger.Info($"The service is {(serviceMandatory ? "mandatory" : "optional")} and {(serviceAvailable ? "available." : "not available. All service-related operations will be ignored!")}");
}
}
public void Repeat()
{
// TODO
}
public void Revert()
{
logger.Info("Closing service connection...");
@ -93,5 +85,19 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
}
}
}
private void LogException(Exception e)
{
var message = "Failed to connect to the service component!";
if (serviceMandatory)
{
logger.Error(message, e);
}
else
{
logger.Info($"{message} Reason: {e.Message}");
}
}
}
}

View file

@ -8,8 +8,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
@ -21,52 +21,56 @@ namespace SafeExamBrowser.Runtime.Behaviour
{
internal class RuntimeController : IRuntimeController
{
private Queue<IOperation> operations;
private ILogger logger;
private IRuntimeInfo runtimeInfo;
private IRuntimeWindow runtimeWindow;
private IServiceProxy serviceProxy;
private ISettingsRepository settingsRepository;
private IShutdownController shutdownController;
private IStartupController startupController;
private IOperationSequence operationSequence;
private Action terminationCallback;
private IText text;
private IUserInterfaceFactory uiFactory;
public RuntimeController(
ILogger logger,
IOperationSequence operationSequence,
IRuntimeInfo runtimeInfo,
IServiceProxy serviceProxy,
ISettingsRepository settingsRepository,
IShutdownController shutdownController,
IStartupController startupController,
Action terminationCallback,
IText text,
IUserInterfaceFactory uiFactory)
{
this.logger = logger;
this.operationSequence = operationSequence;
this.runtimeInfo = runtimeInfo;
this.serviceProxy = serviceProxy;
this.settingsRepository = settingsRepository;
this.shutdownController = shutdownController;
this.startupController = startupController;
this.terminationCallback = terminationCallback;
this.text = text;
this.uiFactory = uiFactory;
operations = new Queue<IOperation>();
}
public bool TryInitializeApplication(Queue<IOperation> operations)
public bool TryStart(Queue<IOperation> operations)
{
var success = startupController.TryInitializeApplication(operations);
logger.Info("--- Initiating startup procedure ---");
var success = operationSequence.TryPerform(operations);
runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text);
if (success)
{
this.operations = new Queue<IOperation>(operations);
logger.Info("--- Application successfully initialized! ---");
logger.Log(string.Empty);
logger.Subscribe(runtimeWindow);
StartSession();
}
else
{
logger.Info("--- Application startup aborted! ---");
logger.Log(string.Empty);
}
return success;
@ -95,9 +99,11 @@ namespace SafeExamBrowser.Runtime.Behaviour
{
runtimeWindow.Hide();
}
terminationCallback.Invoke();
}
public void FinalizeApplication()
public void Terminate()
{
StopSession();
@ -108,7 +114,20 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Unsubscribe(runtimeWindow);
runtimeWindow.Close();
shutdownController.FinalizeApplication(new Queue<IOperation>(operations.Reverse()));
logger.Log(string.Empty);
logger.Info("--- Initiating shutdown procedure ---");
var success = operationSequence.TryRevert();
if (success)
{
logger.Info("--- Application successfully finalized! ---");
}
else
{
logger.Info("--- Shutdown procedure failed! ---");
}
}
private void StopSession()

View file

@ -14,9 +14,9 @@ using System.Windows;
using SafeExamBrowser.Configuration;
using SafeExamBrowser.Configuration.Settings;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Core.Behaviour;
using SafeExamBrowser.Core.Behaviour.Operations;
using SafeExamBrowser.Core.Communication;
using SafeExamBrowser.Core.I18n;
@ -52,11 +52,10 @@ namespace SafeExamBrowser.Runtime
InitializeLogging();
var text = new Text(logger);
var operationSequence = new OperationSequence(logger, runtimeInfo, text, uiFactory);
var serviceProxy = new ServiceProxy(new ModuleLogger(logger, typeof(ServiceProxy)), "net.pipe://localhost/safeexambrowser/service");
var shutdownController = new ShutdownController(logger, runtimeInfo, text, uiFactory);
var startupController = new StartupController(logger, runtimeInfo, systemInfo, text, uiFactory);
RuntimeController = new RuntimeController(new ModuleLogger(logger, typeof(RuntimeController)), runtimeInfo, serviceProxy, settingsRepository, shutdownController, startupController, Application.Current.Shutdown, text, uiFactory);
RuntimeController = new RuntimeController(logger, operationSequence, runtimeInfo, serviceProxy, settingsRepository, Application.Current.Shutdown, text, uiFactory);
StartupOperations = new Queue<IOperation>();
StartupOperations.Enqueue(new I18nOperation(logger, text));