// Copyright (c) 2015-2017 schick Informatik // Description: Bearbeitung von Antworten (dateibasiert..) using bsmd.database; using System; using System.Collections.Generic; using System.IO; using log4net; using System.Xml.Linq; namespace bsmd.hisnord { public class Response { private static ILog _log = LogManager.GetLogger(typeof(Response)); public static void ReadAnswers() { foreach (string answerFile in Directory.GetFiles(Properties.Settings.Default.AnswerDir)) { bool isOK = true; // Informationen aus dem Dateinamen // Meldetyp_Referenz_ID_Timestamp.xml string bareFileName = Path.GetFileNameWithoutExtension(answerFile); string[] fileNameElems = bareFileName.Split('_'); if (fileNameElems.Length < 4) { _log.WarnFormat("ANSWER file {0}.xml has an invalid file name", bareFileName); isOK = false; } else { int prozessStatus; if (!Int32.TryParse(fileNameElems[fileNameElems.Length - 1], out prozessStatus)) { _log.WarnFormat("ANSWER file {0}.xml has no process status at the end (2..6)", bareFileName); isOK = false; } else { long timestampMilliSecs; if (!Int64.TryParse(fileNameElems[fileNameElems.Length - 2], out timestampMilliSecs)) { _log.WarnFormat("ANSWER file {0}.xml has no readable timestamp", bareFileName); isOK = false; } else { string refId = fileNameElems[fileNameElems.Length - 3]; string meldeTyp = fileNameElems[fileNameElems.Length - 4]; if (fileNameElems.Length == 5) meldeTyp = string.Format("{0}_{1}", fileNameElems[fileNameElems.Length - 5], meldeTyp); // TODO: klären was man hier liest: reguläre Antwort oder Schnittstellenfehler // XML Linq statt Serialisierung try { XElement xml = XElement.Load(answerFile); // declare Namespaces XNamespace ns1 = "http://api.national-single-window.de/visitIdRequest"; XNamespace ns6 = "http://api.national-single-window.de/receipt"; //XNamespace ns15 = "http://api.national-single-window.de/statusForClientRequestId"; XNamespace soap = "http://schemas.xmlsoap.org/soap/envelope/"; XNamespace ns15 = "http://api.national-single-window.de/visitIdResponse"; if (xml.Name == "SystemError") { // Fehlernachricht SystemError systemError = SystemError.createFromXml(xml); if (systemError != null) { MessageCore aCore = DBManager.Instance.GetMessageCoreById(systemError.MessageCoreId); if (aCore != null) { _log.InfoFormat("SystemError received for Core [{0}], IMO {1} ETA {2}: {3}", aCore.Id, aCore.IMO, aCore.ETADisplay, systemError.ErrorMessage); } else { _log.WarnFormat("SystemError received for unknown core {0}: {1}", systemError.MessageCoreId, systemError.ErrorMessage); } // trotzdem immer speichern DBManager.Instance.Save(systemError); } } else { // NSW Rückmeldung NSWResponse nswResponse = new NSWResponse(xml); // Rückmeldung auswerten if (nswResponse.MessageCoreId.HasValue) { MessageCore core = DBManager.Instance.GetMessageCoreById(nswResponse.MessageCoreId.Value); if (core != null) { List messages = DBManager.Instance.GetMessagesForCore(core, DBManager.MessageLoad.ALL); if(nswResponse.NotificationClass == Message.NotificationClass.VISIT) { if ((nswResponse.Status == "ACCEPTED") && !nswResponse.VisitId.IsNullOrEmpty()) core.VisitId = nswResponse.VisitId; } if(nswResponse.NotificationClass == Message.NotificationClass.TRANSIT) { if ((nswResponse.Status == "ACCEPTED") && !nswResponse.TransitId.IsNullOrEmpty()) core.TransitId = nswResponse.TransitId; } core.BSMDStatusInternal = MessageCore.BSMDStatus.RESPONDED; DBManager.Instance.Save(core); // now find the message that was meant.. foreach (Message aMessage in messages) { if (aMessage.MessageNotificationClass == nswResponse.NotificationClass) { if (nswResponse.Status != null) { bool isAccepted = (nswResponse.Status == "ACCEPTED"); if(isAccepted) { aMessage.Status = Message.MessageStatus.ACCEPTED; aMessage.InternalStatus = Message.BSMDStatus.CONFIRMED; if (nswResponse.Violations.Count > 0) { aMessage.InternalStatus = Message.BSMDStatus.VIOLATION; aMessage.StatusInfo = "Violations reported"; } aMessage.ReceivedAt = nswResponse.ReceiveAt; } else { aMessage.Status = Message.MessageStatus.REJECTED; aMessage.InternalStatus = Message.BSMDStatus.ERROR; aMessage.StatusInfo = "Errors reported"; } DBManager.Instance.Save(aMessage); } #region Error / Violation handling foreach (MessageError existingError in aMessage.ErrorList) DBManager.Instance.Delete(existingError); foreach (MessageViolation existingViolation in aMessage.ViolationList) DBManager.Instance.Delete(existingViolation); foreach (MessageError messageError in nswResponse.Errors) { messageError.MessageHeaderId = aMessage.Id.Value; messageError.MessageHeader = aMessage; DBManager.Instance.Save(messageError); } foreach (MessageViolation messageViolation in nswResponse.Violations) { messageViolation.MessageHeaderId = aMessage.Id.Value; messageViolation.MessageHeader = aMessage; DBManager.Instance.Save(messageViolation); } #endregion } } } else { _log.ErrorFormat("cannot find core for id {0}", nswResponse.MessageCoreId); } } else { _log.ErrorFormat("received response without suitable conveyance code, request id {0}", nswResponse.ClientRequestId); isOK = false; } } } catch(Exception ex) { _log.WarnFormat("Exception deserializing ANSWER file: {0}", ex.ToString()); isOK = false; } } } } if(isOK) { // archive file File.Move(answerFile, Path.Combine(Properties.Settings.Default.AnswerArchiveDir, Path.GetFileName(answerFile))); } else { // save in separate folder (to look at it later?) File.Move(answerFile, Path.Combine(Properties.Settings.Default.AnswerCorruptDir, Path.GetFileName(answerFile))); } } } } }