git_bsmd/nsw/Source/SendNSWMessageService/NSWSendService.cs

288 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.IO;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using log4net;
using bsmd.database;
using bsmd.dbh;
using bsmd.hisnord;
namespace SendNSWMessageService
{
public partial class NSWSendService : ServiceBase
{
private Timer _timer;
private object _timerlock = new object();
private bool processRunning = false;
private ILog _log = LogManager.GetLogger(typeof(NSWSendService));
public NSWSendService()
{
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
InitializeComponent();
}
protected override void OnStart(string[] args)
{
this.EventLog.Source = this.ServiceName;
this.EventLog.Log = "Application";
this.Init(args);
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
string version = fvi.FileVersion;
this.EventLog.WriteEntry("NSW Send Service started", EventLogEntryType.Information);
_log.InfoFormat("NSW Send Service started. v.{0}", version);
this.DoOnce();
}
public void Init(string[] args)
{
this._timer = new Timer();
this._timer.Interval = Properties.Settings.Default.SleepSeconds * 1000;
this._timer.Elapsed += _timer_Elapsed;
this._timer.Enabled = true;
}
public void DoOnce()
{
this._timer_Elapsed(null, null);
}
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (this._timerlock)
{
if (this.processRunning) return;
else this.processRunning = true;
}
bool sendSucceeded;
if (DBManager.Instance.Connect(Properties.Settings.Default.ConnectionString))
{
// Datenbank auf zu sendende Objekte überprüfen und laden
List<MessageCore> coresMarkedForSending = DBManager.Instance.GetMessageCoresByStatus(MessageCore.BSMDStatus.TOSEND);
foreach (MessageCore core in coresMarkedForSending)
{
List<Message> messages = DBManager.Instance.GetMessagesForCore(core);
if (core.InitialHIS == Message.NSWProvider.DUDR)
{
// Rostocker: wir senden alle Nachrichten auf einmal
sendSucceeded = bsmd.hisnord.Request.Send(messages);
if (!sendSucceeded) core.BSMDStatusInternal = MessageCore.BSMDStatus.FAILURE;
else core.BSMDStatusInternal = MessageCore.BSMDStatus.SENT;
DBManager.Instance.Save(core);
}
else
{
List<Message> toSendMessageList = new List<Message>();
if ((core.IsTransit && core.TransitId.IsNullOrEmpty()) ||
(!core.IsTransit && core.VisitId.IsNullOrEmpty()))
{
foreach (Message message in messages)
{
if ((message.MessageNotificationClass == Message.NotificationClass.VISIT) ||
(message.MessageNotificationClass == Message.NotificationClass.TRANSIT))
{
if ((message.InternalStatus == Message.BSMDStatus.UNDEFINED) ||
(message.InternalStatus == Message.BSMDStatus.PREPARE) ||
(message.InternalStatus == Message.BSMDStatus.TOSEND))
{
_log.Debug("Visit/Transit not found, SENDING VISIT/TRANSIT message");
if (message.HIS == Message.NSWProvider.UNDEFINED)
message.HIS = core.InitialHIS;
toSendMessageList.Add(message);
}
}
}
}
else // eine VISIT/TRANSIT Id ist vorhanden, die Daten können gesendet werden
{
// Änderung Sept 15: versendet werden alle Nachrichten, die *nicht* bestätigt sind
// also auch alles was auf in bearbeitung / Korrektur etc steht
// Einzig bleibt die Frage offen, was mit Nachrichten passiert, die über das UI
// nachträglich geändert werden. Ich denke hier muss in dashface ggf. der Status
// wieder auf PREPARE gesetzt werden
_log.Debug("Visit/Transit found, SENDING DATA messages");
foreach (Message message in messages)
{
// Wenn das ein Transit ist, werden nicht erforderliche Meldeklassen übersprungen
if (core.IsTransit)
{
if ((message.MessageNotificationClass == Message.NotificationClass.BKRD) ||
(message.MessageNotificationClass == Message.NotificationClass.PRE72H) ||
(message.MessageNotificationClass == Message.NotificationClass.TIEFD) ||
(message.MessageNotificationClass == Message.NotificationClass.NAME) ||
(message.MessageNotificationClass == Message.NotificationClass.INFO) ||
(message.MessageNotificationClass == Message.NotificationClass.POBD) ||
(message.MessageNotificationClass == Message.NotificationClass.ATA) ||
(message.MessageNotificationClass == Message.NotificationClass.ATD) ||
(message.MessageNotificationClass == Message.NotificationClass.LADG) ||
(message.MessageNotificationClass == Message.NotificationClass.SERV) ||
(message.MessageNotificationClass == Message.NotificationClass.WAS) ||
(message.MessageNotificationClass == Message.NotificationClass.TOWD))
continue;
}
// Visit/Transit Meldeklassen werden nicht erneut übertragen
if ((message.MessageNotificationClass == Message.NotificationClass.VISIT) ||
(message.MessageNotificationClass == Message.NotificationClass.TRANSIT))
continue;
// Wenn kein Gefahrgut gemeldet ist soll die Meldeklasse gar nicht gesendet werden
if((message.MessageNotificationClass == Message.NotificationClass.HAZA) ||
(message.MessageNotificationClass == Message.NotificationClass.HAZD))
{
if (message.Elements.Count > 0)
{
HAZ haz = message.Elements[0] as HAZ;
if (haz != null)
{
if (haz.NoDPGOnBoardOnArrival ?? false) continue;
}
}
}
// ATD wird nur gesendet, wenn weniger als 60 Minuten in der Zukunft
if(message.MessageNotificationClass == Message.NotificationClass.ATD)
{
if (message.Elements.Count > 0)
{
bsmd.database.ATD atd = message.Elements[0] as bsmd.database.ATD;
if (!atd.ATDPortOfCall.HasValue) continue;
if ((atd.ATDPortOfCall.Value - DateTime.UtcNow).TotalMinutes > 60) continue;
}
}
if (message.InternalStatus != Message.BSMDStatus.CONFIRMED)
//(message.InternalStatus == Message.BSMDStatus.PREPARE) ||
//(message.InternalStatus == Message.BSMDStatus.TOSEND))
{
if (message.HIS == Message.NSWProvider.UNDEFINED)
message.HIS = core.InitialHIS;
toSendMessageList.Add(message);
}
}
}
foreach (Message message in toSendMessageList)
{
try
{
_log.InfoFormat("Sending {0} message to {1}",
message.MessageNotificationClass.ToString(), message.HIS.ToString());
sendSucceeded = false;
// switch über passendes HIS / Schnittstelle
switch (message.HIS)
{
case Message.NSWProvider.DBH:
sendSucceeded = bsmd.dbh.Request.SendMessage(message);
if (!sendSucceeded)
message.InternalStatus = Message.BSMDStatus.SEND_FAILED;
break;
case Message.NSWProvider.DAKOSY:
sendSucceeded = bsmd.dakosy.Request.Send(message);
if (!sendSucceeded) message.InternalStatus = Message.BSMDStatus.SEND_FAILED;
break;
default:
_log.WarnFormat("Initial HIS not specified for message {0}", message.Id);
break;
}
if (sendSucceeded)
{
// alte Fehlerliste entfernen (die Antwort kann praktisch noch nicht da sein)
// vor dem Versenden zu entfernen halte ich für doof, wenn das Versenden scheitert
foreach (MessageError messageError in message.ErrorList)
DBManager.Instance.Delete(messageError);
foreach (MessageViolation messageViolation in message.ViolationList)
DBManager.Instance.Delete(messageViolation);
_log.Info("send successful, saving message.");
message.InternalStatus = Message.BSMDStatus.SENT;
message.SentAt = DateTime.Now;
}
DBManager.Instance.Save(message);
}
catch (Exception ex)
{
_log.ErrorFormat("SENDING message {0}: {1}", message.Id.ToString(), ex.Message);
}
}
if (toSendMessageList.Count > 0)
{
core.BSMDStatusInternal = MessageCore.BSMDStatus.SENT;
DBManager.Instance.Save(core);
}
}
}
// Auf erhaltene Visit-Ids prüfen (HIS-NORD)
bsmd.hisnord.Request.ReadAnswers();
DBManager.Instance.Disconnect();
}
else
{
_log.Fatal("database connection failure, stopping service");
this.EventLog.WriteEntry("NSW Send Service stopped: DB connection failed", EventLogEntryType.Error);
this.Stop();
}
lock (this._timerlock)
{
this.processRunning = false;
}
}
protected override void OnPause()
{
this._timer.Stop();
}
protected override void OnContinue()
{
this._timer.Start();
}
protected override void OnStop()
{
this._timer.Enabled = false;
this.EventLog.WriteEntry("NSW Send Service stopped.", EventLogEntryType.Information);
_log.Info("NSW Send Service stopped");
}
}
}