/** * 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); }
/** * Construct a SpineSOAPRequest 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 SpineSOAPRequest(SdsTransmissionDetails s, SpineHL7Message m) { if (bootException != null) throw bootException; SDSconnection c = ConnectionManager.getInstance().SdsConnection; type = Sendable.SOAP; myAsid = c.MyAsid; messageid = Guid.NewGuid().ToString().ToUpper(); lock (messageid) { if (myIp == null) { ConnectionManager cm = ConnectionManager.getInstance(); if (cm.MyIp == null) { try { IPAddress[] addresses = Dns.GetHostAddresses(""); myIp = addresses[0].ToString(); } catch (Exception e) { bootException = e; throw e; } if (myIp == null) { bootException = new Exception("No non-localhost IP interfaces found"); throw bootException; } } else { myIp = cm.MyIp; } } if (template == null) { Assembly assembly = Assembly.GetExecutingAssembly(); StreamReader sr = new StreamReader(assembly.GetManifestResourceStream(SOAPREQUESTTEMPLATE)); StringBuilder sb = new StringBuilder(); try { String line = null; while ((line = sr.ReadLine()) != null) { sb.Append(line); sb.Append("\r\n"); } template = sb.ToString(); } catch (Exception e) { bootException = e; throw e; } } } transmissionDetails = s; hl7Message = m; string svcurl = c.resolveUrl(s.SvcIA); if (svcurl == null) resolvedUrl = s.Url; else resolvedUrl = svcurl; }
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]); }
/** * Construct a SpineSOAPRequest 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 SpineSOAPRequest(SdsTransmissionDetails s, SpineHL7Message m) { if (bootException != null) { throw bootException; } SDSconnection c = ConnectionManager.getInstance().SdsConnection; type = Sendable.SOAP; myAsid = c.MyAsid; messageid = Guid.NewGuid().ToString().ToUpper(); lock (messageid) { if (myIp == null) { ConnectionManager cm = ConnectionManager.getInstance(); if (cm.MyIp == null) { try { IPAddress[] addresses = Dns.GetHostAddresses(""); myIp = addresses[0].ToString(); } catch (Exception e) { bootException = e; throw e; } if (myIp == null) { bootException = new Exception("No non-localhost IP interfaces found"); throw bootException; } } else { myIp = cm.MyIp; } } if (template == null) { Assembly assembly = Assembly.GetExecutingAssembly(); StreamReader sr = new StreamReader(assembly.GetManifestResourceStream(SOAPREQUESTTEMPLATE)); StringBuilder sb = new StringBuilder(); try { String line = null; while ((line = sr.ReadLine()) != null) { sb.Append(line); sb.Append("\r\n"); } template = sb.ToString(); } catch (Exception e) { bootException = e; throw e; } } } transmissionDetails = s; hl7Message = m; string svcurl = c.resolveUrl(s.SvcIA); if (svcurl == null) { resolvedUrl = s.Url; } else { resolvedUrl = svcurl; } }
/** * 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); }