2019-08-03 13:49:06 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using ln.logging;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2019-08-06 00:26:47 +02:00
|
|
|
|
using System.Security.Authentication.ExtendedProtection.Configuration;
|
2019-08-03 13:49:06 +02:00
|
|
|
|
|
|
|
|
|
namespace ln.application.service
|
|
|
|
|
{
|
|
|
|
|
public abstract class ApplicationServiceBase : IDisposable
|
|
|
|
|
{
|
2019-08-06 00:26:47 +02:00
|
|
|
|
public int TimeOut { get; set; } = 30000;
|
2019-08-03 13:49:06 +02:00
|
|
|
|
|
|
|
|
|
public String ServiceName { get; protected set; }
|
|
|
|
|
public virtual bool IsAlive => ((ServiceThread != null) && ServiceThread.IsAlive);
|
|
|
|
|
|
2019-08-06 00:26:47 +02:00
|
|
|
|
public virtual bool IsReady => IsAlive && ready;
|
|
|
|
|
bool ready;
|
|
|
|
|
|
2019-08-03 13:49:06 +02:00
|
|
|
|
public bool StopRequested { get; protected set; }
|
|
|
|
|
public Thread ServiceThread { get; protected set; }
|
|
|
|
|
|
|
|
|
|
public string ServiceStateText { get; protected set; }
|
|
|
|
|
|
|
|
|
|
public IApplicationInterface CurrentApplicationInterface { get; protected set; }
|
|
|
|
|
|
|
|
|
|
public Type[] DependingServiceTypes => dependingServiceTypes.ToArray();
|
|
|
|
|
HashSet<Type> dependingServiceTypes = new HashSet<Type>();
|
|
|
|
|
|
|
|
|
|
public ApplicationServiceBase(String serviceName)
|
|
|
|
|
{
|
|
|
|
|
ServiceName = serviceName;
|
|
|
|
|
ServiceStateText = "Initialized";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
ServiceStateText = "Disposed";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void DependOnService<S>() => dependingServiceTypes.Add(typeof(S));
|
|
|
|
|
|
|
|
|
|
public T Dependency<T>() where T : ApplicationServiceBase
|
|
|
|
|
{
|
|
|
|
|
T serviceBase = (T)CurrentApplicationInterface.ServiceContainer[typeof(T)].ServiceBase;
|
|
|
|
|
if (serviceBase == null)
|
|
|
|
|
throw new EntryPointNotFoundException(String.Format("depending service not found: {0}",typeof(T).ToString()));
|
|
|
|
|
|
|
|
|
|
return serviceBase;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void ServiceMain(IApplicationInterface applicationInterface) => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
public virtual bool Start(IApplicationInterface applicationInterface, String[] arguments)
|
|
|
|
|
{
|
|
|
|
|
if (IsAlive)
|
|
|
|
|
throw new NotSupportedException("Service is already alive");
|
|
|
|
|
|
|
|
|
|
CurrentApplicationInterface = applicationInterface;
|
|
|
|
|
|
|
|
|
|
foreach (Type dep in dependingServiceTypes)
|
|
|
|
|
{
|
|
|
|
|
ServiceDefinition depService = CurrentApplicationInterface.ServiceContainer[dep];
|
|
|
|
|
if (!depService.IsAlive)
|
|
|
|
|
{
|
|
|
|
|
CurrentApplicationInterface.ServiceContainer.Start(depService);
|
|
|
|
|
if (!depService.IsAlive)
|
|
|
|
|
{
|
|
|
|
|
Logging.Log(LogLevel.ERROR, "service {0} could not start depending service {1}", ServiceName, depService.ServiceClassName);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-06 00:26:47 +02:00
|
|
|
|
lock (depService.ServiceBase)
|
|
|
|
|
{
|
|
|
|
|
if (!depService.ServiceBase.IsReady)
|
|
|
|
|
{
|
|
|
|
|
Monitor.Wait(depService.ServiceBase, TimeOut);
|
|
|
|
|
if (!depService.ServiceBase.IsReady)
|
|
|
|
|
{
|
|
|
|
|
Logging.Log(LogLevel.ERROR, "service {0} was waiting too long for depending service {1}", ServiceName, depService.ServiceClassName);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-03 13:49:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-08-06 00:26:47 +02:00
|
|
|
|
ready = false;
|
2019-08-03 13:49:06 +02:00
|
|
|
|
StopRequested = false;
|
|
|
|
|
ServiceThread = new Thread(() => ServiceMain(applicationInterface));
|
|
|
|
|
ServiceThread.Start();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual bool Stop() => Stop(false);
|
|
|
|
|
public virtual bool Stop(bool force)
|
|
|
|
|
{
|
|
|
|
|
if (IsAlive)
|
|
|
|
|
{
|
|
|
|
|
StopRequested = true;
|
|
|
|
|
lock (ServiceThread)
|
|
|
|
|
{
|
|
|
|
|
Monitor.PulseAll(ServiceThread);
|
|
|
|
|
}
|
|
|
|
|
ServiceThread.Join(TimeOut);
|
|
|
|
|
if (IsAlive && force)
|
|
|
|
|
{
|
|
|
|
|
Logging.Log(LogLevel.INFO, "Service did not shutdown, enforcing {0}",ServiceName);
|
|
|
|
|
ServiceThread.Abort();
|
|
|
|
|
ServiceThread.Join(TimeOut);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ServiceThread.IsAlive)
|
|
|
|
|
CurrentApplicationInterface = null;
|
|
|
|
|
|
2019-08-06 00:26:47 +02:00
|
|
|
|
ready = false;
|
2019-08-03 13:49:06 +02:00
|
|
|
|
return !ServiceThread.IsAlive;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-06 00:26:47 +02:00
|
|
|
|
protected void Ready()
|
|
|
|
|
{
|
|
|
|
|
lock (this)
|
|
|
|
|
{
|
|
|
|
|
ready = true;
|
|
|
|
|
Monitor.PulseAll(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-03 13:49:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|