#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 /// /// Der Linienname ergibt sich aus der SetupCenter Konfiguration. Es darf nur eine Linie geben. /// private OibClient _oibClient; private static List 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 /// /// Public Constructor for WindowsService. /// - Put all of your Initialization code here. /// 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; } /// /// The Main Thread: This is where your Service is Run. /// 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 } /// /// OnStart(): Put startup code here /// - Start threads, get inital data, etc. /// /// protected override void OnStart(string[] args) { InitService(); base.OnStart(args); } /// /// OnStop(): Put your stop code here /// - Stop threads, set final data, etc. /// protected override void OnStop() { ShutdownService(); base.OnStop(); } /// /// 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. /// protected override void OnShutdown() { ShutdownService(); base.OnShutdown(); } /// /// Dieser Adapter übernimmt die Steuerung der Subscriptions und der Endpoints /// 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(); 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 versionKeySet = new HashSet(); 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(); } } }