219 lines
11 KiB
C#
219 lines
11 KiB
C#
// Copyright (c) 2020-present schick Informatik
|
|
// Description: Verarbeitung von empfangenen Rückmeldungen
|
|
|
|
using bsmd.database;
|
|
using log4net;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text.RegularExpressions;
|
|
using System.Xml.Serialization;
|
|
|
|
namespace bsmd.dbh
|
|
{
|
|
internal static class ResponseUtil
|
|
{
|
|
private static readonly ILog _log = LogManager.GetLogger(typeof(ResponseUtil));
|
|
private static readonly Regex _regexFilename = new Regex(@".*NSW\.DBH\.BSMD(MAERSK)?\.(.*)\.xml");
|
|
|
|
internal static bool Read(string inputFile)
|
|
{
|
|
bool result = false;
|
|
if(!inputFile.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_log.ErrorFormat("no xml file: {0}", inputFile);
|
|
return result;
|
|
}
|
|
|
|
Match m = _regexFilename.Match(inputFile);
|
|
if(!m.Success) {
|
|
_log.WarnFormat("returned file doesn't follow naming convention NSW.DBH.BSMD(MAERSK)?.*:{0}", inputFile);
|
|
return result;
|
|
}
|
|
|
|
// Achtung! Die laufende Nummer der rücklaufenden Datei ist _nicht_ dieselbe und kann zur Identifikation der Meldeklasse
|
|
// nicht verwendet werden
|
|
|
|
string fileSeqString = m.Groups[2].Value;
|
|
|
|
if(!Int32.TryParse(fileSeqString, out int fileSeqNum))
|
|
{
|
|
_log.ErrorFormat("matched file sequence number couldn't be parsed: {0}", fileSeqString);
|
|
return result;
|
|
}
|
|
|
|
bsmd.dbh.Response.Root root = null;
|
|
try
|
|
{
|
|
XmlSerializer serializer = new XmlSerializer(typeof(bsmd.dbh.Response.Root));
|
|
using (Stream s = new FileStream(inputFile, FileMode.Open))
|
|
{
|
|
root = (bsmd.dbh.Response.Root) serializer.Deserialize(s);
|
|
}
|
|
|
|
Message sentMessage = null;
|
|
MessageCore aCore = null;
|
|
|
|
if(Guid.TryParse(root.SenderReference, out Guid refGuid))
|
|
{
|
|
// load message(s?) by file seq string
|
|
sentMessage = DBManager.Instance.GetMessageById(refGuid) as Message;
|
|
if (sentMessage == null)
|
|
{
|
|
_log.ErrorFormat("cannot find a message for file sequence number {0}", fileSeqNum);
|
|
return result;
|
|
}
|
|
|
|
aCore = DBManager.Instance.GetMessageCoreById(sentMessage.MessageCoreId.Value);
|
|
if (aCore == null)
|
|
{
|
|
_log.ErrorFormat("There is no core with id {0}", sentMessage.MessageCoreId.Value);
|
|
return result;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_log.ErrorFormat("sender ref {0} is no guid", root.SenderReference);
|
|
return result;
|
|
}
|
|
|
|
MessageTelemetry.Dequeue(Message.NSWProvider.DBH, sentMessage);
|
|
|
|
switch(root.Type)
|
|
{
|
|
case Response.RootType.VISIT:
|
|
if (aCore.VisitId.IsNullOrEmpty() && !root.VisitId.IsNullOrEmpty())
|
|
{
|
|
aCore.VisitId = root.VisitId;
|
|
sentMessage.SendSuccess = true;
|
|
sentMessage.Status = Message.MessageStatus.ACCEPTED;
|
|
sentMessage.InternalStatus = Message.BSMDStatus.CONFIRMED;
|
|
_log.InfoFormat("Received Visit-Id {0} for core {1}", root.VisitId, aCore.Id);
|
|
}
|
|
break;
|
|
case Response.RootType.TRANSIT:
|
|
if (aCore.TransitId.IsNullOrEmpty() && !root.TransitId.IsNullOrEmpty())
|
|
{
|
|
aCore.TransitId = root.TransitId;
|
|
sentMessage.SendSuccess = true;
|
|
sentMessage.Status = Message.MessageStatus.ACCEPTED;
|
|
sentMessage.InternalStatus = Message.BSMDStatus.CONFIRMED;
|
|
_log.InfoFormat("Received Transit-Id {0} for core {1}", root.TransitId, aCore.Id);
|
|
}
|
|
break;
|
|
case Response.RootType.DATA:
|
|
if(root.ReportingClassesFull?.ReportingClass.Length > 0)
|
|
{
|
|
_log.InfoFormat("Message {0} confirmed (full), {1} messages", sentMessage.MessageNotificationClassDisplay, root.Messages?.Length);
|
|
sentMessage.SendSuccess = true;
|
|
sentMessage.Status = Message.MessageStatus.ACCEPTED;
|
|
sentMessage.InternalStatus = Message.BSMDStatus.CONFIRMED;
|
|
}
|
|
if (root.ReportingClassesPartial?.ReportingClass.Length > 0)
|
|
{
|
|
_log.WarnFormat("Message {0} confirmed (partial), {1} messages", sentMessage.MessageNotificationClassDisplay, root.Messages?.Length);
|
|
sentMessage.SendSuccess = true;
|
|
sentMessage.Status = Message.MessageStatus.ACCEPTED;
|
|
sentMessage.InternalStatus = Message.BSMDStatus.VIOLATION;
|
|
}
|
|
if (root.ReportingClassesError?.ReportingClass.Length > 0)
|
|
{
|
|
_log.ErrorFormat("Message {0} rejected, {1} messages", sentMessage.MessageNotificationClassDisplay, root.Messages?.Length);
|
|
sentMessage.SendSuccess = false;
|
|
sentMessage.Status = Message.MessageStatus.REJECTED;
|
|
sentMessage.InternalStatus = Message.BSMDStatus.ERROR;
|
|
sentMessage.StatusInfo = "Errors reported";
|
|
}
|
|
break;
|
|
case Response.RootType.RESET:
|
|
if(root.ReportingClassesResetted?.ReportingClass.Length > 0)
|
|
{
|
|
_log.InfoFormat("Message {0} RESET confirmed, {1} messages", sentMessage.MessageNotificationClassDisplay, root.Messages?.Length);
|
|
sentMessage.SendSuccess = false; // bestätigter Reset setzt grünen Buppel zurück
|
|
sentMessage.Status = Message.MessageStatus.ACCEPTED;
|
|
sentMessage.InternalStatus = Message.BSMDStatus.CONFIRMED;
|
|
}
|
|
break;
|
|
case Response.RootType.CANCEL:
|
|
_log.InfoFormat("Core {0} CANCEL confirmed", aCore.DisplayId);
|
|
aCore.BSMDStatusInternal = MessageCore.BSMDStatus.RESPONDED;
|
|
break;
|
|
}
|
|
|
|
// "alte" Meldungen entfernen
|
|
foreach (MessageError existingError in sentMessage.ErrorList)
|
|
DBManager.Instance.Delete(existingError);
|
|
|
|
foreach (MessageViolation existingViolation in sentMessage.ViolationList)
|
|
DBManager.Instance.Delete(existingViolation);
|
|
|
|
if (root.Messages != null)
|
|
{
|
|
foreach (Response.RootMessage rootMessage in root.Messages)
|
|
{
|
|
_log.InfoFormat("Message[{0}]: {1} {2} {3}", rootMessage.ID, rootMessage.Type, rootMessage.Location, rootMessage.Text);
|
|
switch (rootMessage.Type)
|
|
{
|
|
case Response.RootMessageType.ERROR:
|
|
MessageError me = new MessageError();
|
|
me.MessageHeaderId = sentMessage.Id.Value;
|
|
me.MessageHeader = sentMessage;
|
|
me.ErrorText = rootMessage.Text;
|
|
DBManager.Instance.Save(me);
|
|
break;
|
|
case Response.RootMessageType.VIOLATION:
|
|
MessageViolation mv = new MessageViolation();
|
|
mv.MessageHeaderId = sentMessage.Id.Value;
|
|
mv.MessageHeader = sentMessage;
|
|
mv.ViolationText = rootMessage.Text;
|
|
DBManager.Instance.Save(mv);
|
|
break;
|
|
case Response.RootMessageType.XSD_ERROR:
|
|
MessageError me_xsd = new MessageError();
|
|
me_xsd.MessageHeaderId = sentMessage.Id.Value;
|
|
me_xsd.MessageHeader = sentMessage;
|
|
me_xsd.ErrorText = rootMessage.Text;
|
|
DBManager.Instance.Save(me_xsd);
|
|
break;
|
|
case Response.RootMessageType.INFO:
|
|
// TODO
|
|
break;
|
|
case Response.RootMessageType.WARNING:
|
|
// TODO
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBManager.Instance.Save(sentMessage);
|
|
|
|
// das hier ist too easy, der Core kann nur auf RESPONDED gehen wenn nichts mehr auf TOSEND
|
|
// oder error steht
|
|
List<Message> messages = DBManager.Instance.GetMessagesForCore(aCore, DBManager.MessageLoad.ALL);
|
|
bool somethingStillInToSend = false;
|
|
foreach (Message message in messages)
|
|
{
|
|
if((message.InternalStatus == Message.BSMDStatus.TOSEND) ||
|
|
(message.InternalStatus == Message.BSMDStatus.SENT))
|
|
somethingStillInToSend = true;
|
|
}
|
|
|
|
if (!(aCore.Cancelled ?? false) && !somethingStillInToSend)
|
|
aCore.BSMDStatusInternal = MessageCore.BSMDStatus.RESPONDED;
|
|
|
|
_log.InfoFormat("Core {0} set to status {1}", aCore.DisplayId, aCore.BSMDStatusInternal);
|
|
DBManager.Instance.Save(aCore);
|
|
result = true;
|
|
}
|
|
|
|
catch(Exception ex)
|
|
{
|
|
_log.ErrorFormat("Failed to deserialize return message: {0}", ex.Message);
|
|
return result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|