/// <summary> /// Called when the login fails for some reason. /// </summary> public void HandleLoginFailure(Exception ex) { WmSm.LockNotif(); Debug.Assert(m_ks.LoginStatus == KwsLoginStatus.LoggingIn); // Update our login state. UpdateStateOnLogout(ex); // The events are out of sync. if (m_ks.LoginResult == KwsLoginResult.OOS) { // Request a rebuild. We have to delete both the cached events and // the user data. This is nasty. if (m_cd.MainStatus == KwsMainStatus.Good || m_cd.MainStatus == KwsMainStatus.RebuildRequired) { m_cd.MainStatus = KwsMainStatus.RebuildRequired; m_cd.RebuildFlags = KwsRebuildFlag.FlushKcdData | KwsRebuildFlag.FlushLocalData; } } // Make the workspace work offline if required. The core operations // may have already marked the workspace for removal. if (m_cd.CurrentTask == KwsTask.WorkOnline) { SetUserTask(KwsTask.WorkOffline); RequestTaskSwitch(KwsTask.WorkOffline, ex); } WmSm.UnlockNotif(); }
///////////////////////////////////////////// // Interface methods for external parties. // ///////////////////////////////////////////// /// <summary> /// This method must be called by each application when it has started. /// </summary> public void OnAppStarted() { // The applications are no longer starting. if (m_cd.AppStatus != KwsAppStatus.Starting) { return; } // Not all applications have started. foreach (KwsApp app in m_kws.AppTree.Values) { if (app.AppStatus != KwsAppStatus.Started) { return; } } WmSm.LockNotif(); // All applications are started. m_cd.AppStatus = KwsAppStatus.Started; // Notify the listeners. WmSm.QueueNotif(new KwsSmNotifApp(m_kws, m_cd.AppStatus)); // Let the state machine sort it out. RequestRun("Applications started"); WmSm.UnlockNotif(); }
/// <summary> /// This method should be called when an unexpected failure occurs /// in the workspace. /// </summary> public void HandleMiscFailure(Exception ex) { WmSm.LockNotif(); KLogging.LogException(ex); // We cannot handle failures during task switches. We need the // task switches to succeed to recover from failures. if (m_taskSwitchFlag) { KBase.HandleException(ex, true); } // Increase the severity of the rebuild required if possible. if (m_cd.CurrentTask == KwsTask.Rebuild) { WorsenRebuild(KwsRebuildFlag.FlushKcdData | KwsRebuildFlag.FlushLocalData); } // Stop the workspace if required. SetUserTask(KwsTask.Stop); RequestTaskSwitch(KwsTask.Stop, ex); // Let the state machine sort it out. RequestRun("application failure"); WmSm.UnlockNotif(); }
/// <summary> /// Called when the workspace logs out normally. /// </summary> public void HandleNormalLogout() { WmSm.LockNotif(); Debug.Assert(m_ks.LoginStatus == KwsLoginStatus.LoggingOut); // Update our login state. UpdateStateOnLogout(null); WmSm.UnlockNotif(); }
/// <summary> /// Switch the current task to the task specified. Don't call this /// outside RequestSwitchTask() unless you know what you are doing. /// The state machine will run ASAP to handle the new state. /// </summary> private void SwitchTask(KwsTask task, Exception ex) { // The order of the calls is important here. WmSm.LockNotif(); Debug.Assert(m_taskSwitchFlag == false); m_taskSwitchFlag = true; m_cd.CurrentTask = task; StopAppIfNeeded(ex); DisconnectFromKcdIfNeeded(); LogoutIfNeeded(); StopRebuildIfNeeded(); UpdateKcdEventUpToDateState(); m_kws.OnStateChange(WmStateChange.Transient); RequestRun("task switch to " + task); m_taskSwitchFlag = false; WmSm.QueueNotif(new KwsSmNotifTaskSwitch(m_kws, task, ex)); WmSm.UnlockNotif(); }
/// <summary> /// Called when the workspace becomes logged in. /// </summary> public void HandleLoginSuccess() { WmSm.LockNotif(); Debug.Assert(m_ks.LoginStatus == KwsLoginStatus.LoggingIn); // We're now logged in. m_ks.LoginStatus = KwsLoginStatus.LoggedIn; // Update the event up to date state. UpdateKcdEventUpToDateState(); // Notify the listeners. WmSm.QueueNotif(new KwsSmNotifKcdLogin(m_kws, m_ks.LoginStatus, null)); // Let the state machine sort it out. RequestRun("Workspace login success"); WmSm.UnlockNotif(); }
/// <summary> /// Request a switch to the task specified, if possible. 'Ex' is /// non-null if the task switch is occurring because an error occurred. /// </summary> public void RequestTaskSwitch(KwsTask task, Exception ex) { WmSm.LockNotif(); try { // Validate. if (m_taskSwitchFlag || task == KwsTask.Stop && !CanStop() || task == KwsTask.Spawn && !CanSpawn() || task == KwsTask.Rebuild && !CanRebuild() || task == KwsTask.WorkOffline && !CanWorkOffline() || task == KwsTask.WorkOnline && !CanWorkOnline() || task == KwsTask.DeleteLocally && !CanDeleteLocally() || task == KwsTask.DeleteRemotely && !CanDeleteRemotely()) { KLogging.Log("Request to switch to task " + task + " ignored."); return; } KLogging.Log("Switching to task " + task + "."); // Update some state prior to the task switch. if (task == KwsTask.Rebuild) { m_cd.MainStatus = KwsMainStatus.RebuildRequired; m_rebuildStep = KwsRebuildTaskStep.None; } else if (task == KwsTask.WorkOnline) { ResetKcdFailureState(); } else if (task == KwsTask.DeleteLocally) { m_cd.MainStatus = KwsMainStatus.OnTheWayOut; m_kws.AddToKwsRemoveTree(); m_kws.OnStateChange(WmStateChange.Permanent); } else if (task == KwsTask.DeleteRemotely) { ResetKcdFailureState(); m_deleteRemotelyStep = KwsDeleteRemotelyStep.ConnectedAndLoggedOut; } if (task == KwsTask.Spawn || task == KwsTask.Rebuild || task == KwsTask.WorkOffline || task == KwsTask.WorkOnline) { m_cd.LastException = null; m_kws.OnStateChange(WmStateChange.Permanent); } // Perform the task switch, if required. if (task != m_cd.CurrentTask) { SwitchTask(task, ex); } } catch (Exception ex2) { KBase.HandleException(ex2, true); } finally { WmSm.UnlockNotif(); } }