Example #1
0
        /**
         * Construct an EbXmlMessage for sending.
         *
         * @param s An SdSTransmissionDetails instance for recipient information
         * @param m SpineHL7Message instance to be sent
         * @param c Reference to an SDSconnection for resolving URLs
         */
        public EbXmlMessage(SdsTransmissionDetails s, SpineHL7Message m)
        {
            SDSconnection c = ConnectionManager.getInstance().SdsConnection;

            odsCode    = s.Org;
            header     = new EbXmlHeader(this, s);
            type       = EBXML;
            hl7message = m;
            string svcurl = c.resolveUrl(s.SvcIA);

            if (svcurl == null)
            {
                resolvedUrl = s.Url;
            }
            else
            {
                resolvedUrl = svcurl;
            }
            if (s.Retries != SdsTransmissionDetails.NOT_SET)
            {
                retryCount       = s.Retries;
                minRetryInterval = s.RetryInterval;
                persistDuration  = s.PersistDuration;
            }
            attachments = new List <Attachment>();
            persistable = (s.Retries > 0);
        }
Example #2
0
        /**
         * Instantiate the SDSconnection, reading configuration details from the Registry. There is an
         * additional dependency on an external PKCS#12 (.pfx) file that contains the Spine endpoint
         * certificate and key.
         */
        public SDSconnection()
        {
            server          = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, SDS_SERVER_REGVAL, "");
            cacheDir        = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, SDS_CACHE_FILE_REGVAL, "");
            certificateFile = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, SDS_CERT_FILE_REGVAL, "");
            urlResolverFile = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, URL_RESOLVER_FILE, "");
            myAsid          = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, MY_ASID, "");
            myPartyKey      = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, MY_PARTY_KEY, "");
            EbXmlHeader.setMyPartyKey(myPartyKey);

            string s = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, SDS_REFRESH_PERIOD_REGVAL, "");

            loadUrlResolver();

            if (s.Length > 0)
            {
                try
                {
                    cacheRefreshPeriod = Int32.Parse(s);
                }
                catch (Exception)
                {
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    StringBuilder sb = new StringBuilder("Registry entry ");
                    sb.Append(SDS_REFRESH_PERIOD_REGVAL);
                    sb.Append(" has invalid non-integer value '");
                    sb.Append(s);
                    sb.Append("'. Using default value ");
                    sb.Append(DEFAULT_REFRESH_PERIOD);
                    sb.Append(" hours instead");
                    logger.WriteEntry(sb.ToString(), EventLogEntryType.Warning);
                }
            }
            s           = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, SDS_OPENTEST_REGVAL, "");
            opentest    = (s.ToUpper().StartsWith("Y"));
            serviceRoot = (opentest) ? OPENTEST_SERVICES_ROOT : CIS_SERVICES_ROOT;
            if (server.Length == 0)
            {
                if (cacheDir.Length == 0)
                {
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    logger.WriteEntry("Neither LDAP server name nor cache file registry entries are set - cannot resolve anything!", EventLogEntryType.Error);
                }
                else
                {
                    cache = new SDScache(cacheDir, cacheRefreshPeriod);
                }
            }
            else
            {
                if (cacheDir.Length == 0)
                {
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    logger.WriteEntry("Cache file registry entry not set: all queries will be resolved directly from SDS and this MAY impact performance", EventLogEntryType.Warning);
                }
                else
                {
                    cache = new SDScache(cacheDir, cacheRefreshPeriod);
                }
            }
            if (certificateFile.Length > 0)
            {
                try
                {
                    String certPass = (string)Registry.GetValue(SDS_CONNECTION_REGSITRY_KEY, SDS_CERT_PASS_REGVAL, "");
                    certificate = new X509Certificate(certificateFile, certPass);
                }
                catch (Exception e)
                {
                    EventLog logger = new EventLog("Application");
                    logger.Source = LOGSOURCE;
                    StringBuilder sb = new StringBuilder("Certificate ");
                    sb.Append(certificateFile);
                    sb.Append(" failed to load: ");
                    sb.Append(e.ToString());
                    sb.Append(" - no lookups can be made against SDS");
                    logger.WriteEntry(sb.ToString(), EventLogEntryType.Error);
                }
            }
            else
            {
                EventLog logger = new EventLog("Application");
                logger.Source = LOGSOURCE;
                logger.WriteEntry("No certificate provided - queries will be resolved from cache only", EventLogEntryType.Warning);
            }
        }
Example #3
0
        /**
         * Used to assemble an EbXmlMessage from the given Stream, which has been accepted from the network.
         * This expects to get the inbound HTTP stream (or at least an SslStream) from the start, because it
         * begins processing with the HTTP POST.
         */
        public EbXmlMessage(Stream instream)
        {
            // Assemble from network - note that Spine messages are NOT chunked
            //
            string headerline = null;
            Dictionary <string, string> headers = new Dictionary <string, string>();

            while ((headerline = readLine(instream)).Trim().Length != 0)
            {
                if (headerline.StartsWith("POST"))
                {
                    int firstSpace  = headerline.IndexOf(' ');
                    int secondSpace = headerline.IndexOf(' ', firstSpace + 1);
                    if ((firstSpace == -1) || (secondSpace == -1))
                    {
                        throw new Exception("Malformed HTTP request line, can't parse POST context path");
                    }
                    receivedContextPath = headerline.Substring(firstSpace, secondSpace - firstSpace);
                }
                else
                {
                    int colon = headerline.IndexOf(":");
                    if (colon == -1)
                    {
                        throw new Exception("Malformed HTTP header - no field/data delimiter colon");
                    }
                    headers.Add(headerline.Substring(0, colon).ToUpper(), headerline.Substring(colon + 1).Trim());
                }
            }
            string ctype = headers["CONTENT-TYPE"];

            if (ctype == null)
            {
                throw new Exception("Malformed HTTP headers - no Content-Type found");
            }
            if (ctype.Contains("multipart/related"))
            {
                mimeboundary = setMimeBoundary(ctype);
            }
            receivedHost = headers["HOST"];
            string clen = headers["CONTENT-LENGTH"];

            if (clen == null)
            {
                throw new Exception("Malformed HTTP headers - no Content-Length found");
            }
            int contentlength = Int32.Parse(clen);

            soapAction = headers["SOAPACTION"];
            soapAction = soapAction.Replace('"', ' ').Trim();

            // There is a bug in Spine-hosted services that turns a SOAPaction starting with
            // "urn:" into "urn:urn:" - fix this if we find it.
            //
            if (soapAction.StartsWith("urn:urn:"))
            {
                soapAction = soapAction.Substring(4);
            }

            // Read content-length bytes and parse out the various parts of the
            // received message.
            // TODO: Put in proper handling.
            //
            Byte[] wire      = new Byte[contentlength];
            int    bytesRead = 0;

            while (bytesRead < contentlength)
            {
                bytesRead += instream.Read(wire, bytesRead, contentlength - bytesRead);
            }
            string msg = Encoding.UTF8.GetString(wire);

            // Split on the mimeboundary. "msg" doesn't contain the HTTP headers so we should
            // just be able to walk through the attachments. If we can't, report an exception
            //
            int startPosition = msg.IndexOf(mimeboundary, 0);

            if (startPosition == -1)
            {
                // Need to handle the case where the content is
                // actually an asynchronous ebXML ack.
                //
                // If content-type is text/xml and soapaction contains Acknowledgment or MessageError,
                // it is an ack/nack. If we get one of these we need to log it and tell the connection
                // manager about it. But we don't need to do any further processing.
                //
                if (ctype.ToLower().StartsWith("text/xml"))
                {
                    if (soapAction.Contains("Acknowledgment"))
                    {
                        // Remove from requests, and exit
                        string a = EbXmlAcknowledgment.getAckedMessageId(msg);
                        if (a == null)
                        {
                            EventLog logger = new EventLog("Application");
                            logger.Source = ConnectionManager.LOGSOURCE;
                            StringBuilder sb = new StringBuilder("Failed to extract message id reference from Acknowledgment: ");
                            sb.Append(msg);
                            logger.WriteEntry(sb.ToString(), EventLogEntryType.Error);
                            return;
                        }
                        ConnectionManager cm = ConnectionManager.getInstance();
                        cm.registerAck(a);
                        return;
                    }
                    if (soapAction.Contains("MessageError"))
                    {
                        // Remove from requests, and exit
                        string a = EbXmlAcknowledgment.getAckedMessageId(msg);
                        if (a == null)
                        {
                            EventLog logger = new EventLog("Application");
                            logger.Source = ConnectionManager.LOGSOURCE;
                            StringBuilder sb = new StringBuilder("Failed to extract message id reference from MessageError: ");
                            sb.Append(msg);
                            logger.WriteEntry(sb.ToString(), EventLogEntryType.Error);
                            return;
                        }
                        EventLog l = new EventLog("Application");
                        l.Source = ConnectionManager.LOGSOURCE;
                        StringBuilder sbe = new StringBuilder("EbXML MessageError received: ");
                        sbe.Append(msg);
                        l.WriteEntry(sbe.ToString(), EventLogEntryType.Error);

                        ConnectionManager cm = ConnectionManager.getInstance();
                        cm.registerAck(a);
                        return;
                    }
                }
                throw new Exception("Malformed message");
            }
            int  endPosition    = 0;
            int  partCount      = 0;
            bool gotEndBoundary = false;

            do
            {
                startPosition += mimeboundary.Length;
                endPosition    = msg.IndexOf(mimeboundary, startPosition);
                if (endPosition == -1)
                {
                    gotEndBoundary = true;
                }
                else
                {
                    switch (partCount)
                    {
                    case 0:
                        header = new EbXmlHeader(msg.Substring(startPosition, endPosition - startPosition));
                        if (header.Timestamp != null)
                        {
                            started = DateTime.Parse(header.Timestamp);
                            // We don't know how many attempts were actually made, so assume
                            // only one try at the start time.
                            //
                            lastTry = DateTime.Parse(header.Timestamp);
                            tries   = 1;
                        }
                        break;

                    case 1:
                        hl7message = new SpineHL7Message(msg.Substring(startPosition, endPosition - startPosition));
                        break;

                    default:
                        if (attachments == null)
                        {
                            attachments = new List <Attachment>();
                        }
                        // IMPROVEMENT: Make this more flexible to be able to support multiple types of
                        // ITK trunk message, just in case
                        //
                        if (soapAction.Contains("COPC_IN000001GB01"))
                        {
                            attachments.Add(new ITKDistributionEnvelopeAttachment(msg.Substring(startPosition, endPosition - startPosition)));
                        }
                        else
                        {
                            attachments.Add(new GeneralAttachment(msg.Substring(startPosition, endPosition - startPosition)));
                        }
                        break;
                    }
                    partCount++;
                    startPosition = endPosition;
                }
            }while (!gotEndBoundary);
//            persistDuration = (int)(ConnectionManager.getInstance().getPersistDuration(header.SvcIA).TotalSeconds);
        }
        /**
         * Used to assemble an EbXmlMessage from the given Stream, which has been accepted from the network.
         * This expects to get the inbound HTTP stream (or at least an SslStream) from the start, because it
         * begins processing with the HTTP POST.
         */
        public EbXmlMessage(Stream instream)
        {
            // Assemble from network - note that Spine messages are NOT chunked
            //
            string headerline = null;
            Dictionary<string, string> headers = new Dictionary<string, string>();
            while ((headerline = readLine(instream)).Trim().Length != 0)
            {
                if (headerline.StartsWith("POST"))
                {
                    int firstSpace = headerline.IndexOf(' ');
                    int secondSpace = headerline.IndexOf(' ', firstSpace + 1);
                    if ((firstSpace == -1) || (secondSpace == -1))
                        throw new Exception("Malformed HTTP request line, can't parse POST context path");
                    receivedContextPath = headerline.Substring(firstSpace, secondSpace - firstSpace);
                }
                else
                {
                    int colon = headerline.IndexOf(":");
                    if (colon == -1)
                    {
                        throw new Exception("Malformed HTTP header - no field/data delimiter colon");
                    }
                    headers.Add(headerline.Substring(0, colon).ToUpper(), headerline.Substring(colon + 1).Trim());
                }
            }
            string ctype = headers["CONTENT-TYPE"];
            if (ctype == null) {
                throw new Exception("Malformed HTTP headers - no Content-Type found");
            }
            if (ctype.Contains("multipart/related")) {
                mimeboundary = setMimeBoundary(ctype);
            }
            receivedHost = headers["HOST"];
            string clen = headers["CONTENT-LENGTH"];
            if (clen == null)
            {
                throw new Exception("Malformed HTTP headers - no Content-Length found");
            }
            int contentlength = Int32.Parse(clen);
            soapAction = headers["SOAPACTION"];
            soapAction = soapAction.Replace('"', ' ').Trim();

            // There is a bug in Spine-hosted services that turns a SOAPaction starting with
            // "urn:" into "urn:urn:" - fix this if we find it.
            //
            if (soapAction.StartsWith("urn:urn:"))
                soapAction = soapAction.Substring(4);

            // Read content-length bytes and parse out the various parts of the
            // received message.
            // TODO: Put in proper handling.
            //
            Byte[] wire = new Byte[contentlength];
            int bytesRead = 0;
            while (bytesRead < contentlength)
            {
                bytesRead += instream.Read(wire, bytesRead, contentlength - bytesRead);
            }
            string msg = Encoding.UTF8.GetString(wire);

            // Split on the mimeboundary. "msg" doesn't contain the HTTP headers so we should
            // just be able to walk through the attachments. If we can't, report an exception
            //
            int startPosition = msg.IndexOf(mimeboundary, 0);
            if (startPosition == -1)
            {
                // Need to handle the case where the content is
                // actually an asynchronous ebXML ack.
                //
                // If content-type is text/xml and soapaction contains Acknowledgment or MessageError,
                // it is an ack/nack. If we get one of these we need to log it and tell the connection
                // manager about it. But we don't need to do any further processing.
                //
                if (ctype.ToLower().StartsWith("text/xml"))
                {
                    if (soapAction.Contains("Acknowledgment"))
                    {
                        // Remove from requests, and exit
                        string a = EbXmlAcknowledgment.getAckedMessageId(msg);
                        if (a == null)
                        {
                            EventLog logger = new EventLog("Application");
                            logger.Source = ConnectionManager.LOGSOURCE;
                            StringBuilder sb = new StringBuilder("Failed to extract message id reference from Acknowledgment: ");
                            sb.Append(msg);
                            logger.WriteEntry(sb.ToString(), EventLogEntryType.Error);
                            return;
                        }
                        ConnectionManager cm = ConnectionManager.getInstance();
                        cm.registerAck(a);
                        return;
                    }
                    if (soapAction.Contains("MessageError"))
                    {
                        // Remove from requests, and exit
                        string a = EbXmlAcknowledgment.getAckedMessageId(msg);
                        if (a == null)
                        {
                            EventLog logger = new EventLog("Application");
                            logger.Source = ConnectionManager.LOGSOURCE;
                            StringBuilder sb = new StringBuilder("Failed to extract message id reference from MessageError: ");
                            sb.Append(msg);
                            logger.WriteEntry(sb.ToString(), EventLogEntryType.Error);
                            return;
                        }
                        EventLog l = new EventLog("Application");
                        l.Source = ConnectionManager.LOGSOURCE;
                        StringBuilder sbe = new StringBuilder("EbXML MessageError received: ");
                        sbe.Append(msg);
                        l.WriteEntry(sbe.ToString(), EventLogEntryType.Error);

                        ConnectionManager cm = ConnectionManager.getInstance();
                        cm.registerAck(a);
                        return;
                    }
                }
                throw new Exception("Malformed message");
            }
            int endPosition = 0;
            int partCount = 0;
            bool gotEndBoundary = false;
            do
            {
                startPosition += mimeboundary.Length;
                endPosition = msg.IndexOf(mimeboundary, startPosition);
                if (endPosition == -1)
                {
                    gotEndBoundary = true;
                }
                else
                {
                    switch (partCount)
                    {
                        case 0:
                            header = new EbXmlHeader(msg.Substring(startPosition, endPosition - startPosition));
                            if (header.Timestamp != null)
                            {
                                started = DateTime.Parse(header.Timestamp);
                                // We don't know how many attempts were actually made, so assume
                                // only one try at the start time.
                                //
                                lastTry = DateTime.Parse(header.Timestamp);
                                tries = 1;
                            }
                            break;
                        case 1:
                            hl7message = new SpineHL7Message(msg.Substring(startPosition, endPosition - startPosition));
                            break;
                        default:
                            if (attachments == null)
                                attachments = new List<Attachment>();
                            // IMPROVEMENT: Make this more flexible to be able to support multiple types of
                            // ITK trunk message, just in case
                            //
                            if (soapAction.Contains("COPC_IN000001GB01"))
                            {
                                attachments.Add(new ITKDistributionEnvelopeAttachment(msg.Substring(startPosition, endPosition - startPosition)));
                            }
                            else
                            {
                                attachments.Add(new GeneralAttachment(msg.Substring(startPosition, endPosition - startPosition)));
                            }
                            break;
                    }
                    partCount++;
                    startPosition = endPosition;
                }
            }
            while (!gotEndBoundary);
            //            persistDuration = (int)(ConnectionManager.getInstance().getPersistDuration(header.SvcIA).TotalSeconds);
        }
 /**
  * Construct an EbXmlMessage for sending.
  *
  * @param s An SdSTransmissionDetails instance for recipient information
  * @param m SpineHL7Message instance to be sent
  * @param c Reference to an SDSconnection for resolving URLs
  */
 public EbXmlMessage(SdsTransmissionDetails s, SpineHL7Message m)
 {
     SDSconnection c = ConnectionManager.getInstance().SdsConnection;
     odsCode = s.Org;
     header = new EbXmlHeader(this, s);
     type = EBXML;
     hl7message = m;
     string svcurl = c.resolveUrl(s.SvcIA);
     if (svcurl == null)
         resolvedUrl = s.Url;
     else
         resolvedUrl = svcurl;
     if (s.Retries != SdsTransmissionDetails.NOT_SET)
     {
         retryCount = s.Retries;
         minRetryInterval = s.RetryInterval;
         persistDuration = s.PersistDuration;
     }
     attachments = new List<Attachment>();
     persistable = (s.Retries > 0);
 }