Пример #1
0
        /**
         * Checks to see if the given EbXmlMessage is acknowledged asynchronously, and just returns
         * if not. Otherwise, constructs an EbXMLAcknowledgment addressed to the sender of "msg",
         * and calls the ConnectionManager to send it.
         *
         * @param EbXmlMessage to acknowledge
         */
        private void doAsynchronousAck(EbXmlMessage msg)
        {
            if (msg == null)
            {
                return;
            }
            if (!msg.Header.DuplicateElimination)
            {
                return;
            }
            if (msg.Header.SyncReply)
            {
                return;
            }

            StringBuilder                 a          = new StringBuilder(makeEbXmlAck(msg, false));
            ConnectionManager             cm         = ConnectionManager.getInstance();
            SDSconnection                 sds        = cm.SdsConnection;
            string                        ods        = msg.Header.FromPartyKey.Substring(0, msg.Header.FromPartyKey.IndexOf("-"));
            List <SdsTransmissionDetails> sdsdetails = sds.getTransmissionDetails(ACKSERVICE, ods, null, msg.Header.FromPartyKey);

            a.Replace("__CPA_ID__", sdsdetails[0].CPAid);
            EbXmlAcknowledgment ack = new EbXmlAcknowledgment(a.ToString());

            ack.setHost(sdsdetails[0].Url);
            cm.send(ack, sdsdetails[0]);
        }
Пример #2
0
        /** Called by the Listener to process a received message. See if this
         * is a response and correlate with requests if it is, otherwise add
         * to the received messages queue. This is called by Listener.processMessage()
         * which is invoked in its own thread, so we don't need to spawn any new
         * threads here.
         *
         * @param Received message
         */
        internal void receive(Sendable s)
        {
            if (s.SoapAction.Contains("service:Acknowledgment") || s.SoapAction.Contains("service:MessageError"))
            {
                // Asynchronous ack/nack. Remove from request list and exit.
                //
                EbXmlMessage m = (EbXmlMessage)s;
                if (!requests.Remove(m.Header.ConversationId))
                {
                    // Log receipt of ack/nack that doesn't belong to us...
                    // Note: This may be legitimate in a clustered MHS or if in- and out-bound
                    // nodes are separate.
                    //
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    StringBuilder sbe = new StringBuilder("Unexpected response ");
                    sbe.Append(s.SoapAction);
                    sbe.Append(" with conversation id ");
                    sbe.Append(m.Header.ConversationId);
                    sbe.Append(" that was not sent from here.");
                    logger.WriteEntry(sbe.ToString(), EventLogEntryType.Information);
                }

                depersist(m.Header.ConversationId);
                return;
            }
            ISpineHandler h = null;

            try
            {
                h = handlers[s.SoapAction];
            }
            catch (KeyNotFoundException)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                StringBuilder sbe = new StringBuilder("Unknown SOAP action ");
                sbe.Append(s.SoapAction);
                sbe.Append(" using DefaultFileSaveSpineHandler");
                logger.WriteEntry(sbe.ToString(), EventLogEntryType.FailureAudit);
                h = defaultSpineHandler;
            }
            try
            {
                h.handle(s);
            }
            catch (Exception e)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                StringBuilder sbe = new StringBuilder("Exception handling  ");
                sbe.Append(s.SoapAction);
                sbe.Append(" : ");
                sbe.Append(e.ToString());
                logger.WriteEntry(sbe.ToString(), EventLogEntryType.FailureAudit);
            }
        }
Пример #3
0
        /**
         * Removes a reliable request from the retry list. Does nothing if null is passed
         * or if the message id is not known to the retry list.
         *
         * @param a Message id of the request to remove.
         */
        internal void removeRequest(EbXmlMessage a)
        {
            if (a == null)
            {
                return;
            }
            string m = a.getMessageId();

            if (requests.ContainsKey(m))
            {
                requests.Remove(m);
                depersist(a);
            }
        }
Пример #4
0
        /**
         * Checks to see if the EbXmlMessage should be acknowledged synchronously, and just returns
         * a zero-length string if not. Otherwise, makes an ebXML acknowledgment and returns it as
         * a string.
         *
         * @param EbXmlMessage to acknowledge
         */
        private string makeSynchronousAck(EbXmlMessage msg)
        {
            if (!msg.Header.DuplicateElimination)
            {
                return(EMPTY_RESPONSE);
            }
            if (!msg.Header.SyncReply)
            {
                return(EMPTY_RESPONSE);
            }

            StringBuilder hdr = new StringBuilder(ACK_HTTP_HEADER);
            string        ack = makeEbXmlAck(msg, true);

            hdr.Replace("__CONTENT_LENGTH__", ack.Length.ToString());
            hdr.Append(ack);
            return(hdr.ToString());
        }
Пример #5
0
 /**
  * TODO: Constructs an asynchronous ebXML error message. Where do we get error information from ?
  *
  * @param EbXml message to NACK
  */
 private void doAsynchronousNack(EbXmlMessage msg)
 {
     // If "msg" is an ack or message error
     if (msg.Header == null)
     {
         return;
     }
     // If "msg" is "unreliable"
     if (!msg.Header.DuplicateElimination)
     {
         return;
     }
     // If we've already returned the ack synchronously
     if (msg.Header.SyncReply)
     {
         return;
     }
 }
Пример #6
0
        /**
         * Assembles an ebXML acknowledgment.
         */
        private string makeEbXmlAck(EbXmlMessage msg, bool replaceCpaId)
        {
            StringBuilder sb = new StringBuilder(ebxmlacktemplate);

            sb.Replace("__FROM_PARTY_ID__", msg.Header.FromPartyKey);
            //sb.Replace("__FROM_PARTY_ID__", msg.Header.ToPartyKey);
            string mp = ConnectionManager.getInstance().SdsConnection.MyPartyKey;

            sb.Replace("__TO_PARTY_ID__", mp);
            sb.Replace("__ORIGINAL_MESSAGE_ID__", msg.getMessageId());
            sb.Replace("__CONVERSATION_ID__", msg.Header.ConversationId);
            if (replaceCpaId)
            {
                sb.Replace("__CPA_ID__", msg.Header.CpaId);
            }
            sb.Replace("__ACK_MESSAGE_ID__", System.Guid.NewGuid().ToString().ToUpper());
            sb.Replace("__ACK_TIMESTAMP__", DateTime.Now.ToString(EbXmlHeader.ISO8601DATEFORMAT));
            return(sb.ToString());
        }
Пример #7
0
        private void depersist(EbXmlMessage a)
        {
            string pfile = messageDirectory + a.getOdsCode() + "_" + a.getMessageId();

            try
            {
                if (File.Exists(pfile))
                {
                    File.Delete(pfile);
                }
            }
            catch (Exception e)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                StringBuilder sbe = new StringBuilder("Unexpected error ");
                sbe.Append(e.ToString());
                sbe.Append(" de-persisting message ");
                sbe.Append(pfile);
                logger.WriteEntry(sbe.ToString(), EventLogEntryType.Error);
            }
        }
Пример #8
0
        /** Called at start-up if the system needs to load any persisted, reliable messages
         * for sending. This applies the persist duration for the message type to the declared
         * timestamp, and will run the expire() method on anything that has expired whilst
         * the MHS was down.
         */
        public void loadPersistedMessages()
        {
            string[]     files = Directory.GetFiles(messageDirectory);
            EbXmlMessage ebxml = null;

            foreach (String f in files)
            {
                using (FileStream fs = new FileStream(f, FileMode.Open))
                {
                    try
                    {
                        ebxml = new EbXmlMessage(fs);

                        // "f" is now of the form "odscode_messageid" so get the ods code and set it here.
                        string ods = f.Substring(0, f.IndexOf("_")).Substring(f.LastIndexOf("\\") + 1);
                        ebxml.setOdsCode(ods);

                        // Do an SDS lookup and populate retry interval, persist duration
                        // and retry cound in ebxml.

                        List <SdsTransmissionDetails> sdsdetails = sdsConnection.getTransmissionDetails(ebxml.Header.SvcIA, ods, ebxml.HL7Message.ToAsid, ebxml.Header.ToPartyKey);
                        if (sdsdetails.Count == 0)
                        {
                            throw new Exception("Cannot resolve SDS details for persisted message: " + f);
                        }
                        if (sdsdetails.Count > 1)
                        {
                            throw new Exception("Ambiguous SDS details for persisted message: " + f);
                        }

                        SdsTransmissionDetails sds = sdsdetails[0];
                        ebxml.PersistDuration = sds.PersistDuration;
                        ebxml.RetryCount      = sds.Retries;
                        ebxml.RetryInterval   = sds.RetryInterval;
                    }
                    catch (Exception e)
                    {
                        EventLog logger = new EventLog("Application");
                        logger.Source = LOGSOURCE;
                        StringBuilder sbe = new StringBuilder("Failed to load persisted ebXml message ");
                        sbe.Append(f);
                        sbe.Append(" due to exception ");
                        sbe.Append(e.Message);
                        sbe.Append(" at ");
                        sbe.Append(e.StackTrace);
                        logger.WriteEntry(sbe.ToString(), EventLogEntryType.FailureAudit);
                        continue;
                    }
                }
                DateTime check      = DateTime.Now;
                TimeSpan pd         = getPersistDuration(ebxml.Header.SvcIA);
                DateTime expiryTime = ebxml.Started.Add(pd);
                if (expiryTime.CompareTo(check) < 0)
                {
                    depersist(ebxml);
                    ebxml.Expire();
                }
                else
                {
                    requests.Add(ebxml.getMessageId(), ebxml);
                }
            }
        }
Пример #9
0
        /**
         * Called in its own thread to process the inbound message on the given socket. Reads the
         * message, returns any synchronous or asynchronous acknowledgment, and logs the message id in the de-duplication list.
         * If the id has not been seen before (according to the list), calls ConnectionManager.receive().
         *
         * @param Clear-text accepted socket
         */
        private void processMessage(Socket s)
        {
            // Log received ebXML message ids and add to it where "duplicate
            // elimination" is set. Do this in memory - if we go down between retries on long-
            // duration interactions we'll incorrectly not detect the duplicate, but that will
            // be a recognised limitation for now, and is supposed to be caught by HL7 de-
            // duplication anyway.
            //
            EbXmlMessage msg = null;

            try
            {
                ConnectionManager cm  = ConnectionManager.getInstance();
                NetworkStream     n   = new NetworkStream(s);
                SslStream         ssl = new SslStream(n, false, validateRemoteCertificate, getLocalCertificate);

                // FIXME: Require client certificate - but leave it for now
                //

                ssl.AuthenticateAsServer(cm.getCertificate());
                msg = new EbXmlMessage(ssl);
                string ack = makeSynchronousAck(msg);
                if (ack != null)
                {
                    ssl.Write(Encoding.UTF8.GetBytes(ack));
                    ssl.Flush();
                }
                ssl.Close();

                // If we have data for it, DateTime.Now + persistDuration. The trouble is that
                // the persistDuration isn't actually carried in the message. Easiest is *probably*
                // to cache SDS details for "my party key" for all received messages, which will
                // require a "tool" to do the calls.
                //
                Dictionary <string, TimeSpan> pd = cm.ReceivedPersistDurations;
                if (pd != null)
                {
                    bool notSeenBefore = true;
                    lock (requestLock)
                    {
                        notSeenBefore = (!receivedIds.ContainsKey(msg.Header.MessageId));
                    }
                    if (notSeenBefore)
                    {
                        try
                        {
                            // TimeSpan ts = pd[msg.SoapAction];
                            TimeSpan ts         = pd[msg.Header.SvcIA];
                            DateTime expireTime = DateTime.Now;
                            expireTime = expireTime.Add(ts);
                            lock (requestLock)
                            {
                                receivedIds.Add(msg.Header.MessageId, expireTime);
                            }
                        }
                        catch (KeyNotFoundException) { }
                        cm.receive(msg);
                    }
                    // No "else" - if the message id is in the "receivedIds" set then we want
                    // to do the ack but nothing else.
                }
                else
                {
                    cm.receive(msg);
                }
            }
            catch (Exception e)
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                StringBuilder sb = new StringBuilder("Error receiving message from");
                sb.Append(s.RemoteEndPoint.ToString());
                sb.Append(" : ");
                sb.Append(e.ToString());
                logger.WriteEntry(sb.ToString(), EventLogEntryType.Error);
                if (msg != null)
                {
                    doAsynchronousNack(msg);
                }
                return;
            }
            doAsynchronousAck(msg);
        }
Пример #10
0
        static void Main(string[] args)
        {
            ConnectionManager cm = ConnectionManager.getInstance();
            SDSconnection     c  = cm.SdsConnection;

            cm.listen();
            // cm.loadPersistedMessages();

//           List<SdsTransmissionDetails> sdsdetails = c.getTransmissionDetails("urn:nhs:names:services:pdsquery:QUPA_IN000008UK02", "YES", null, null);
// /            List<SdsTransmissionDetails> sdsdetails = c.getTransmissionDetails("urn:nhs:names:services:pdsquery:QUPA_IN020000UK31", "YEA", "631955299542", null);
//            List<SdsTransmissionDetails> sdsdetails = c.getTransmissionDetails("urn:nhs:names:services:mm:PORX_IN020101UK31", "YEA", "631955299542", null);

            /*          string qstring = null;
             *        using (StreamReader rdr = File.OpenText(@"c:\test\data\query.txt"))
             *        {
             *            qstring = rdr.ReadToEnd();
             *        }
             *        // SpineHL7Message msg = new SpineHL7Message("QUPA_IN020000UK31", qstring);
             *        //SpineHL7Message msg = new SpineHL7Message("PORX_IN020101UK31", qstring);
             *        SpineHL7Message msg = new SpineHL7Message("QUPA_IN000008UK02", qstring);
             *        SpineSOAPRequest req = new SpineSOAPRequest(sdsdetails[0], msg);
             *        msg.ToAsid = sdsdetails[0].Asid[0];
             *        msg.MyAsid = c.MyAsid;
             *        msg.IsQuery = true;
             *        //EbXmlMessage eb = new EbXmlMessage(sdsdetails[0], msg, c);
             *
             *        MemoryStream ms = new MemoryStream();
             *         req.write(ms);
             *        //eb.write(ms);
             *        ms.Seek(0, SeekOrigin.Begin);
             *        StreamReader sr = new StreamReader(ms);
             *        string s = sr.ReadToEnd();
             *
             *        cm.send(req, sdsdetails[0]);
             */
            //cm.listen();
//            while (true) ;

//            List<SdsTransmissionDetails> sdsdetails = c.getTransmissionDetails("urn:nhs:names:services:pdsquery:QUPA_IN000008UK02", "YES", null, null);
//            List<SdsTransmissionDetails> sdsdetails = c.getTransmissionDetails("urn:nhs:names:services:pdsquery:QUPA_IN040000UK32", "YES", null, null);
//            List<SdsTransmissionDetails> sdsdetails = c.getTransmissionDetails("urn:nhs:names:services:mm:PORX_IN132004UK30", "YES", null, null);
            List <SdsTransmissionDetails> sdsdetails = c.getTransmissionDetails("urn:nhs:names:services:psis:REPC_IN150015UK05", "YES", null, null);

//            List<SdsTransmissionDetails> sdsdetails = c.getTransmissionDetails("urn:nhs:names:services:pdsquery:QUPA_IN000006UK02", "YES", null, null);
            int i = sdsdetails.Count;

            cm.listen();
            string qstring = null;

            using (StreamReader rdr = File.OpenText(@"c:\test\data\REPC_IN150015UK05_mhstest.xml"))
            {
                qstring = rdr.ReadToEnd();
            }
            SpineHL7Message msg = new SpineHL7Message("REPC_IN150015UK05", qstring);

            msg.ToAsid     = sdsdetails[0].Asid[0];
            msg.MyAsid     = c.MyAsid;
            msg.AuthorRole = "S0080:G0450:R5080";
            msg.AuthorUid  = "687227875014";
            msg.AuthorUrp  = "012345678901";

            EbXmlMessage eb = new EbXmlMessage(sdsdetails[0], msg);
            //          eb.Attachments.Add(deattachment);
            MemoryStream ms = new MemoryStream();

            eb.write(ms);
            ms.Seek(0, SeekOrigin.Begin);
            StreamReader sr = new StreamReader(ms);
            string       s  = sr.ReadToEnd();

            cm.send(eb, sdsdetails[0]);
        }
 private void depersist(EbXmlMessage a)
 {
     string pfile = messageDirectory + a.getOdsCode() + "_" + a.getMessageId();
     try
     {
         if (File.Exists(pfile))
             File.Delete(pfile);
     }
     catch (Exception e)
     {
         EventLog logger = new EventLog("Application");
         logger.Source = LOGSOURCE;
         StringBuilder sbe = new StringBuilder("Unexpected error ");
         sbe.Append(e.ToString());
         sbe.Append(" de-persisting message ");
         sbe.Append(pfile);
         logger.WriteEntry(sbe.ToString(), EventLogEntryType.Error);
     }
 }
 /**
  * Removes a reliable request from the retry list. Does nothing if null is passed
  * or if the message id is not known to the retry list.
  *
  * @param a Message id of the request to remove.
  */
 internal void removeRequest(EbXmlMessage a)
 {
     if (a == null)
         return;
     string m = a.getMessageId();
     if (requests.ContainsKey(m))
     {
         requests.Remove(m);
         depersist(a);
     }
 }
        /** Called at start-up if the system needs to load any persisted, reliable messages
         * for sending. This applies the persist duration for the message type to the declared
         * timestamp, and will run the expire() method on anything that has expired whilst
         * the MHS was down.
         */
        public void loadPersistedMessages()
        {
            string[] files = Directory.GetFiles(messageDirectory);
            EbXmlMessage ebxml = null;
            foreach (String f in files)
            {
                using (FileStream fs = new FileStream(f, FileMode.Open))
                {
                    try
                    {
                        ebxml = new EbXmlMessage(fs);

                        // "f" is now of the form "odscode_messageid" so get the ods code and set it here.
                        string ods = f.Substring(0, f.IndexOf("_")).Substring(f.LastIndexOf("\\") + 1);
                        ebxml.setOdsCode(ods);

                        // Do an SDS lookup and populate retry interval, persist duration
                        // and retry cound in ebxml.

                        List<SdsTransmissionDetails> sdsdetails = sdsConnection.getTransmissionDetails(ebxml.Header.SvcIA, ods, ebxml.HL7Message.ToAsid, ebxml.Header.ToPartyKey);
                        if (sdsdetails.Count == 0)
                            throw new Exception("Cannot resolve SDS details for persisted message: " + f);
                        if (sdsdetails.Count > 1)
                            throw new Exception("Ambiguous SDS details for persisted message: " + f);

                        SdsTransmissionDetails sds = sdsdetails[0];
                        ebxml.PersistDuration = sds.PersistDuration;
                        ebxml.RetryCount = sds.Retries;
                        ebxml.RetryInterval = sds.RetryInterval;
                    }
                    catch(Exception e)
                    {
                        EventLog logger = new EventLog("Application");
                        logger.Source = LOGSOURCE;
                        StringBuilder sbe = new StringBuilder("Failed to load persisted ebXml message ");
                        sbe.Append(f);
                        sbe.Append(" due to exception ");
                        sbe.Append(e.Message);
                        sbe.Append(" at ");
                        sbe.Append(e.StackTrace);
                        logger.WriteEntry(sbe.ToString(), EventLogEntryType.FailureAudit);
                        continue;
                    }
                }
                DateTime check = DateTime.Now;
                TimeSpan pd = getPersistDuration(ebxml.Header.SvcIA);
                DateTime expiryTime = ebxml.Started.Add(pd);
                if (expiryTime.CompareTo(check) < 0)
                {
                    depersist(ebxml);
                    ebxml.Expire();
                }
                else
                {
                    requests.Add(ebxml.getMessageId(), ebxml);
                }
            }
        }