Files
MyMcKesson/TomcatServer/RegistrationServer/RegistrationService.cs
2016-07-27 00:32:34 -04:00

357 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using Pluto.Registration;
using System.Reflection;
using Yaulw.Thread;
namespace RegistrationServer
{
public partial class RegistrationService : ServiceBase
{
#region Internal Consts
// Threshold used to determine if system just rebooted, and service just
// started. We need to wait a little because we need to make sure the Database Server is up
internal const int NUMBER_OF_MINUTES_SERVICE_UP_THRESHOLD = 5;
internal const int NUMBER_OF_MINUTES_SYSTEM_UP_THRESHOLD = 10;
#endregion
#region Internal Statics
/// <summary>
/// Service Start Time
/// </summary>
internal static DateTime ServiceStartDT = DateTime.MinValue;
#endregion
#region Private Members
/// <summary>
/// Check if this is the first time the network got enabled
/// </summary>
private bool FirstTimeNetworkConnected = true;
/// <summary>
/// Was the Channel Activated?
/// </summary>
private bool ROHasBeenActivated = false;
/// <summary>
/// Did a System Reboot just occur?
/// </summary>
private bool SystemJustStarted_SoUseServiceThreshold = false;
private bool ServiceUpTimeReached = false;
private bool SystemThresholdNotReached = true;
/// <summary>
/// Is the Logger Setup?
/// </summary>
private bool LoggerIsSetup = false;
/// <summary>
/// Our Connectivity Timer Thread
/// </summary>
private SingleThreadTimer connectivityTimer = null;
/// <summary>
/// If for some reason the network goes down, we should re-initialize
/// everything as if nothing happened
/// </summary>
private bool NetworkOutageDetected = false;
#endregion
#region Construction
/// <summary>
/// Singleton Instance of the Service
/// </summary>
internal static RegistrationService s_RegistrationService = null;
/// <summary>
/// Constructor
/// </summary>
public RegistrationService()
{
InitializeComponent();
// Log to the Application System Log
this.EventLog.Log = "Application";
s_RegistrationService = this;
// Handle all unexpected errors
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
/// <summary>
/// Unhandled Domain Exception
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = (Exception)e.ExceptionObject;
String msg = "UnhandledException Occured: " + ex.Message + "\n\n" + ex.InnerException.Message;
AppLogError(msg);
}
#endregion
#region Windows Event Logging
internal static void AppLogError(string errMsg)
{
s_RegistrationService.EventLog.WriteEntry(errMsg, EventLogEntryType.Error);
if (Registration.Logger != null)
Registration.Logger.Error(errMsg);
}
internal static void AppLogInfo(string infoMsg)
{
s_RegistrationService.EventLog.WriteEntry(infoMsg, EventLogEntryType.Information);
if (Registration.Logger != null)
Registration.Logger.Info(infoMsg);
}
internal static void AppLogWarning(string warnMsg)
{
s_RegistrationService.EventLog.WriteEntry(warnMsg, EventLogEntryType.Warning);
if (Registration.Logger != null)
Registration.Logger.Info(warnMsg);
}
#endregion
// usefull for debugging Service in visual studio
#if DEBUG
internal void DebugStart(string[] args)
{
DEBUGGING_ONLY.DEBUGSTEP_INTO();
OnStart(args);
}
#endif
#region System / Service Up Time
/// <summary>
/// Get Service UpTime
/// </summary>
/// <returns></returns>
private TimeSpan GetServiceUpTime()
{
return (DateTime.Now - ServiceStartDT);
}
/// <summary>
/// For Service Handling, see if the system has been up long enough
/// Once it becomes true, it will always return true
/// </summary>
private bool HasServiceBeenUpLongEnough()
{
if (!ServiceUpTimeReached)
ServiceUpTimeReached = GetServiceUpTime().TotalMinutes >= NUMBER_OF_MINUTES_SERVICE_UP_THRESHOLD;
return ServiceUpTimeReached;
}
/// <summary>
/// For Error Handling, see if the system has been up till this threshold
/// Once it becomes false, will always return false
/// </summary>
/// <returns></returns>
private bool IsSystemBeenUpWithinMaxThreshold()
{
if (SystemThresholdNotReached)
SystemThresholdNotReached = (Yaulw.Installer.Common.GetSystemUpTime().TotalMinutes <= NUMBER_OF_MINUTES_SYSTEM_UP_THRESHOLD);
return SystemThresholdNotReached;
}
#endregion
/// <summary>
/// Service Start-Up
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
try
{
// Service Started
// System just started, so make sure that service is timing out a little to make
// sure everything is up and running
SystemJustStarted_SoUseServiceThreshold = IsSystemBeenUpWithinMaxThreshold();
AppLogInfo(String.Format("MSLMobile Gateway Service started up at: {0}. System Reboot detected: {1}", DateTime.Now.ToLongTimeString(), SystemJustStarted_SoUseServiceThreshold));
ServiceStartDT = DateTime.Now;
// Internet / Network Connectivity Timer
// * Ran into issues when computer is rebooted, we need certain things working before the service can start,
// * therefore decided to put DataStore Read(), AutoUpdate, RO Connection into a Connection Timer,
// that keeps checking every 10 seconds if we have network connectivity * Enables / Disables RO Channels as needed, just in case *
AppLogInfo("MSLMobile Gateway Service starting connectivity timer.");
connectivityTimer = new SingleThreadTimer(ConnectivityHandler, (uint)TimeSpan.FromSeconds(10).TotalMilliseconds, true);
}
catch (Exception e)
{
AppLogError(String.Format("Service OnStart() Error thrown. Fatal. Can't continue: {0}", e.Message));
this.Stop();
}
}
#region Private Connectivity Timed Thread (runs every 10 Seconds)
/// <summary>
/// Single Threaded Connectivity Handler (Handles Auto-Update, ReadInDataStore(), and RO Channels)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ConnectivityHandler(object sender, Yaulw.Thread.SingleThreadTimer.STElapsedEventArgs e)
{
// System just started, we won't do anyting in here until our
// Service Startup 'NUMBER_OF_MINUTES_SERVICE_UP_THRESHOLD' timeout of is reached
if (SystemJustStarted_SoUseServiceThreshold && !HasServiceBeenUpLongEnough())
return;
// Check Connectivity,
// ~withouth basic networking being up there is nothing really to do here
bool bHasConnection = Yaulw.Net.IPHostHelper.HasConnection();
if (!bHasConnection)
{
DeactivateChannelIfActivated(true);
return;
}
// Always set up the Logger First (Needed for all subsequent DB Calls)
if (!LoggerIsSetup)
{
AppLogInfo("Setting up Logger");
Registration.Setup_Logger();
LoggerIsSetup = true;
}
// * Check to Make sure the System has been up long enough *
// Calling VerifyConnectivity() requires SQL Server to be up
// and running and hence, we can't do it right at service start when the
// server just rebooted, we wait 5 of service uptime to make sure after a server reboot,
// that the services needed are up
if (FirstTimeNetworkConnected)
{
AppLogInfo("System has been up long enough. Starting Initialization.");
// Make sure we can connect to the Database
try
{
if (!DataAccessLayer.VerifyConnectivity())
{
AppLogError("Cannot verify SQL Server Credentials upon initialization. Service must be stopped.");
this.Stop();
}
else
{
AppLogInfo("Success. SQL Server Credentials could connect upon initialization.");
}
}
catch (Exception ex)
{
AppLogError(String.Format("Cannot verify SQL Server Credentials upon initialization '{0}'. Service must be stopped.", ex.Message));
this.Stop();
}
FirstTimeNetworkConnected = false;
return;
}
// We have a valid SQL Server Connection, hence we can continue
if (!FirstTimeNetworkConnected)
{
// If Network disconnection occured, we should try to re-read in everything,
// to make sure we are doing the best we can
if (NetworkOutageDetected)
{
AppLogInfo("Network Outage Detected - Trying to retry connecting to SQL Server");
// Make sure we can connect to the Database
try
{
if (!DataAccessLayer.VerifyConnectivity())
AppLogError("Cannot verify SQL Server Credentials after Network Outage.");
else
AppLogInfo("Success. SQL Server Credentials could connect after Networ Outage.");
}
catch (Exception ex)
{
AppLogError(String.Format("Cannot verify SQL Server Credentials after Network Outage '{0}'.", ex.Message));
}
}
// Activate the RO Channel
ActivateChannelIfNotActivated();
}
}
#endregion
#region Private RO Channel Helpers
/// <summary>
/// Activate all Channel
/// </summary>
private void ActivateChannelIfNotActivated()
{
if (!ROHasBeenActivated)
{
SetPort(Configuration.Port);
ServerChannel.Activate();
ROHasBeenActivated = true;
AppLogInfo(String.Format("MSLMobile Gateway Service Channel Activated on Port:{0}.", Configuration.Port));
NetworkOutageDetected = false;
}
}
/// <summary>
/// Deactivate RO Channel
/// </summary>
private void DeactivateChannelIfActivated(bool bNetworkOutage)
{
if (ROHasBeenActivated)
{
ServerChannel.Deactivate();
ROHasBeenActivated = false;
AppLogInfo("MSLMobile Gateway Service Channel Deactivated.");
NetworkOutageDetected = bNetworkOutage;
}
}
#endregion
// usefull for debugging Service in visual studio
#if DEBUG
internal void DebugStop() { OnStop(); }
#endif
/// <summary>
/// SCM OnStop() call-in
/// </summary>
protected override void OnStop()
{
try
{
// First stop the internal connectivity timer
if (connectivityTimer != null)
{
AppLogInfo("MSLMobile Gateway Service connectivity timer stopped.");
connectivityTimer.Stop();
}
DeactivateChannelIfActivated(false);
AppLogInfo("End DeactivateChannelIfActivated.");
}
catch (Exception) { /* ignore */ }
}
}
}