Files
2025-06-06 09:15:13 +02:00

443 lines
20 KiB
C#

#region Namespace
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security.Principal;
using System.ServiceProcess;
using System.Threading;
using Asm.As.Oib.Client;
using com.itac.mes.imsapi;
using com.itac.mes.imsapi.client.dotnet;
using com.itac.mes.imsapi.domain.container;
using com.itac.mes.simm;
using com.itac.mes.tools;
using Itac.Oib.Simm;
#endregion
namespace com.itac.mes.proxy.winservice
{
public class WindowsService : ServiceBase
{
#region Fields
/// <summary>
/// Der Linienname ergibt sich aus der SetupCenter Konfiguration. Es darf nur eine Linie geben.
/// </summary>
private OibClient _oibClient;
private static List<tools.KeyValue> versionList;
private static IMSApiDotNet imsapi = null;
private IMSApiSessionValidationStruct sessValData = new IMSApiSessionValidationStruct();
private IMSApiSessionContextStruct newSessionContext = null;
private IIMSApiDotNet imsapiproxy = null;
#endregion
#region Static Methods
private static string GetVersionNr()
{
var asm = Assembly.GetExecutingAssembly();
var asmName = asm.GetName();
object[] attribs = asm.GetCustomAttributes(typeof(AssemblyProductAttribute), true);
string productName = String.Empty;
if (attribs.Length > 0)
{
var asmProduct = attribs[0] as AssemblyProductAttribute;
productName = asmProduct.Product;
}
string aVersion = String.Format("{1}.{2}.{3}.{4}",
productName, asmName.Version.Major, asmName.Version.Minor, asmName.Version.Build, asmName.Version.Revision);
string vers = String.Format("{0} - Version: {1}", productName, aVersion);
return (vers);
}
private static string GetFileVersionNr()
{
var asm = Assembly.GetExecutingAssembly();
object[] attribs = asm.GetCustomAttributes(typeof(AssemblyProductAttribute), true);
string productName = String.Empty;
var assembly = Assembly.GetExecutingAssembly();
if (attribs.Length > 0)
{
var asmProduct = attribs[0] as AssemblyProductAttribute;
productName = asmProduct.Product;
}
var fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
// string version = fvi.ProductVersion;
versionList.Add(new tools.KeyValue() { key = productName, value = fvi.ProductVersion });
string version = String.Format("FileVersion: {1}", productName, fvi.ProductVersion);
try
{
String[] xVersion = fvi.Comments.Split();
String[] mesVersion = xVersion[3].Split('=');
versionList.Add(new tools.KeyValue() { key = mesVersion[0], value = mesVersion[1] });
String[] intfVersion = xVersion[4].Split('=');
versionList.Add(new tools.KeyValue() { key = intfVersion[0], value = intfVersion[1] });
}
catch (Exception)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Warning, "unable to extract version information from assembly " + assembly.GetName());
}
return (version);
}
#endregion
/// <summary>
/// Public Constructor for WindowsService.
/// - Put all of your Initialization code here.
/// </summary>
public WindowsService()
{
ServiceName = Constants.SERVICE_NAME;
EventLog.Log = Constants.LOGGER;
// These Flags set whether or not to handle that specific
// type of event. Set to true if you need it, false otherwise.
CanHandlePowerEvent = true;
CanHandleSessionChangeEvent = true;
CanPauseAndContinue = true;
CanShutdown = true;
CanStop = true;
}
/// <summary>
/// The Main Thread: This is where your Service is Run.
/// </summary>
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
if (e.IsTerminating)
{
object o = e.ExceptionObject;
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "### general exception handling ###");
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, o.ToString());
}
};
var service = new WindowsService();
#if (SERVICE)
ServiceBase.Run(service);
#else
service.OnStart(null);
Console.ReadLine();
service.OnStop();
#endif
}
/// <summary>
/// OnStart(): Put startup code here
/// - Start threads, get inital data, etc.
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
InitService();
base.OnStart(args);
}
/// <summary>
/// OnStop(): Put your stop code here
/// - Stop threads, set final data, etc.
/// </summary>
protected override void OnStop()
{
ShutdownService();
base.OnStop();
}
/// <summary>
/// OnShutdown(): Called when the System is shutting down
/// - Put code here when you need special handling
/// of code that deals with a system shutdown, such
/// as saving special data before shutdown.
/// </summary>
protected override void OnShutdown()
{
ShutdownService();
base.OnShutdown();
}
/// <summary>
/// Dieser Adapter übernimmt die Steuerung der Subscriptions und der Endpoints
/// </summary>
private StatisticWorker statisticWorker;
private Thread statisticThread;
private void InitService()
{
// Ausgabe hilfe für xml-Messages
var config = new AppSettingsReader();
try
{
#if (SERVICE)
TraceListener eventLogTraceListener = new EventLogTraceListener(Constants.SERVICE_NAME);
eventLogTraceListener.Filter = new EventTypeFilter(SourceLevels.Information);
LogHandler.addListener(eventLogTraceListener);
#endif
// Der Port an dem der Adapter auf eingehende Verbindungen des iTAC DataInterface lauscht
var clusterNodes = (String)config.GetValue("itac.artes.clusterNodes", typeof(String));
var stationNumber = (String)config.GetValue("stationNumber", typeof(String));
var client = (String)config.GetValue("client", typeof(String));
var transactionCode = (int)config.GetValue("transactionCode", typeof(int));
var factoryElementPathMes = (String)config.GetValue("factoryElementPathMes", typeof(String));
// diese Werte werden alle benötigt...
var oibCoreComuputerName = (String)config.GetValue("OIBCoreHostName", typeof(String));
var setupCenterExternalControlPort = (int)config.GetValue("SetupCenterExternalControlPort", typeof(int));
// check values for those 3 settings (off, MES, SiMM);
ConfigCode quantityMaster = ConfigCode.OFF;
ConfigCode mslMaster = ConfigCode.OFF;
ConfigCode expirationMaster = ConfigCode.OFF;
try
{
quantityMaster = GetCode((String)config.GetValue("QuantityMaster", typeof(String)), "QuantityMaster");
mslMaster = GetCode((String)config.GetValue("MSLMaster", typeof(String)), "MSLMaster");
expirationMaster = GetCode((String)config.GetValue("ExpirationMaster", typeof(String)), "ExpirationMaster");
}
catch (ArgumentException ae)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, getHeadertext("iTAC.SiMM.Application Startup Problem"));
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, ae.Message);
return;
}
string sEmptyContainerCheckInterval = (string)config.GetValue("emptyContainerCheckInterval", typeof(string));
TimeSpan emptyContainerCheckInterval = new TimeSpan(0);
try
{
emptyContainerCheckInterval = TimeSpan.Parse(sEmptyContainerCheckInterval);
}
catch (FormatException)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, getHeadertext("iTAC.SiMM.Application Startup Problem"));
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "invalid value " + sEmptyContainerCheckInterval + " for configParameter emptyContainerCheckInterval");
return;
}
catch (OverflowException)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, getHeadertext("iTAC.SiMM.Application Startup Problem"));
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "invalid value " + sEmptyContainerCheckInterval + " for configParameter emptyContainerCheckInterval");
return;
}
if (emptyContainerCheckInterval.Ticks == 0)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "checking MES for empty containers switched OFF by configuration value");
}
else
{
if (emptyContainerCheckInterval.TotalSeconds < ContainerCheckThread.MIN_INTERVAL_SECONDS)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, getHeadertext("iTAC.SiMM.Application Startup Problem"));
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "minimum value for checking MES for empty containers is " + ContainerCheckThread.MIN_INTERVAL_SECONDS
+ " seconds, but configured is " + emptyContainerCheckInterval.ToString());
return;
}
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "checking MES for empty containers " + emptyContainerCheckInterval.ToString());
// create and start appropriate thread
}
// check that the process is started as administrator or end process with message
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
if (!principal.IsInRole(WindowsBuiltInRole.Administrator))
{
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, getHeadertext("iTAC.SiMM.Application Startup Problem"));
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "");
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "Insufficient privileges!");
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "This process needs to be started with administrative privileges.");
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "Right click on the executable file and select \"Run As Administrator\"");
return;
}
versionList = new List<tools.KeyValue>();
LogHandler.log(Constants.LOGGER, TraceEventType.Information, getHeadertext("iTAC.SIMM.Application"));
LogHandler.log(Constants.LOGGER, TraceEventType.Information, GetVersionNr() + " / " + GetFileVersionNr());
IMSApiDotNet.setProperty("itac.appid", "iTAC_SIMM_Application");
IMSApiDotNet.setProperty("itac.artes.clusternodes", clusterNodes);
imsapi = IMSApiDotNet.loadLibrary();
LogHandler.log(Constants.LOGGER, TraceEventType.Information, getHeadertext("IMS API"));
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "start Initializing IMS API " + clusterNodes);
int result = imsapi.imsapiInit();
if (result != IMSApiDotNetConstants.RES_OK)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Error, "IMS API initialization failed " + clusterNodes + ": " + result);
return;
}
// read values for 'in' and 'inout' arguments
sessValData.stationNumber = stationNumber;
sessValData.stationPassword = "";
sessValData.user = "";
sessValData.password = "";
sessValData.client = client;
sessValData.registrationType = "S";
sessValData.systemIdentifier = "iTAC.SIMM";
result = imsapi.regLogin(sessValData, out newSessionContext);
if (result != IMSApiDotNetConstants.RES_OK)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Error, "IMS API regLogin failed: " + result);
return;
}
ImsApiProxy proxy = new ImsApiProxy(imsapi);
imsapiproxy = (IIMSApiDotNet)proxy.GetTransparentProxy();
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "IMS API initialized");
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in loadedAssemblies)
{
if (assembly.FullName.StartsWith("AsmApi"))
{
AssemblyProductAttribute adAttr = (AssemblyProductAttribute)Attribute.GetCustomAttribute(assembly, typeof(AssemblyProductAttribute));
versionList.Add(new tools.KeyValue() { key = "AsmApi", value = adAttr.Product });
Console.WriteLine("AsmApi" + adAttr.Product);
}
}
LogHandler.log(Constants.LOGGER, TraceEventType.Information, getHeadertext("Simm Application Startup"));
_oibClient = new OibClient("iTAC", "SIMMApplication", oibCoreComuputerName, factoryElementPathMes, true);
/// listener auf externalcontrol bauen
LogHandler.log(Constants.LOGGER, TraceEventType.Information, getHeadertext("SetupCenterExternalControl"));
var oibSetupCenterExternalControlEvents = _oibClient.GetOibSetupCenterExternalControlEvents(setupCenterExternalControlPort, PortsharingMode.WithoutTcpPortsharing);
var setupCenterNotificationClient = _oibClient.GetSetupCenterNotificationClient();
SetupCenterExternalControlReceiver externalcontrolReceiver = new SetupCenterExternalControlReceiver(oibSetupCenterExternalControlEvents, imsapiproxy, newSessionContext,
stationNumber, transactionCode, quantityMaster, mslMaster, expirationMaster);
externalcontrolReceiver.StartReceiver();
// create and start appropriate thread
if (emptyContainerCheckInterval.TotalSeconds >= 10)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Information, getHeadertext("iTAC.SiMM.Application startup container check thread"));
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "checking MES for empty containers interval: " + emptyContainerCheckInterval.ToString());
ContainerCheckThread ctt = new ContainerCheckThread(emptyContainerCheckInterval, imsapiproxy, newSessionContext, setupCenterNotificationClient, stationNumber);
ctt.Start();
}
try
{
HashSet<string> versionKeySet = new HashSet<string>();
versionKeySet.Add("ServiceLocator");
versionKeySet.Add("SIPLACE.SetupCenter.MaterialControl");
var serviceLocator = _oibClient.GetSeriviceLocatorClient();
var allServices = serviceLocator.GetAllServices();
for (int i = 0; i < allServices.Length; i++)
{
var sd = allServices[i];
if (versionKeySet.Contains(sd.ServiceName) && sd.Configuration != null)
{
versionList.Add(new tools.KeyValue() { key = sd.ServiceName, value = sd.ServiceVersion });
}
}
}
catch (Exception)
{
throw;
}
String currentPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "current path = " + currentPath);
var proxyVersions = _oibClient.GetOibProxyVersions();
LogHandler.log(Constants.LOGGER, TraceEventType.Information, getHeadertext("SIMM Proxy Versions"));
foreach (var keyValuePair in proxyVersions)
{
if (!keyValuePair.Key.Equals("AsmApi"))
{
LogHandler.log(Constants.LOGGER, TraceEventType.Information, string.Format("{0,-50} {1,10}", keyValuePair.Key, keyValuePair.Value));
}
}
LogHandler.log(Constants.LOGGER, TraceEventType.Information, getHeadertext("Statistic Thread"));
try
{
statisticWorker = new StatisticWorker();
statisticWorker.setVersionList(versionList);
statisticThread = new Thread(statisticWorker.DoWork);
statisticThread.Start();
LogHandler.log(Constants.LOGGER, TraceEventType.Information, "Statistic thread started! ");
}
catch (Exception e)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "Statistic thread NOT started!", e);
}
LogHandler.log(Constants.LOGGER, TraceEventType.Information, getHeadertext("Initialization completed"));
}
catch (Exception e)
{
LogHandler.log(Constants.LOGGER, TraceEventType.Critical, "Initialization failed! " + e.Message, e);
}
}
private ConfigCode GetCode(string sCodeValue, string sParameterName)
{
foreach (ConfigCode configCode in Enum.GetValues(typeof(ConfigCode)))
{
if (configCode.ToString().Equals(sCodeValue.ToUpper()))
{
return configCode;
}
}
throw new ArgumentException("The value " + sCodeValue + " is invalid for the parameter " + sParameterName);
}
private string getHeadertext(string v)
{
String separator = "-----------------------------------------------------------------------";
if (separator.Length < v.Length)
{
return separator.Substring(0, 10) + " " + v;
}
else
{
return separator.Substring(0, 10) + " " + v + " " + separator.Substring(0, separator.Length - v.Length);
}
}
private void ShutdownService()
{
statisticWorker.RequestStop();
statisticThread.Join();
if (_oibClient != null)
_oibClient.Dispose();
}
}
}