/// <summary> /// Class constructor. /// </summary> /// <param name="messageType">Message Type</param> /// <param name="messageSubType">Message Sub Type</param> public Hl7Message(System.String messageType, System.String messageSubType) { // constructor activities _messageType = messageType; _messageSubType = messageSubType; _segments = new Hashtable(); Hl7Segment segment = new Hl7Segment(0, Hl7SegmentEnum.MSH); _segments.Add(segment.SegmentId.Id, segment); // Set up MSH segment // - use default message delimiters for now Hl7MessageDelimiters messageDelimiters = new Hl7MessageDelimiters(); FieldDelimiter = messageDelimiters.FieldDelimiter; EncodingCharacters = messageDelimiters.ComponentDelimiter + messageDelimiters.RepetitionSeparator + messageDelimiters.EscapeCharacter + messageDelimiters.SubComponentDelimiter; SendingApplication = "DVTK-IHE"; SendingFacility = "DVTK"; ReceivingApplication = "DVTK-IHE"; ReceivingFacility = "DVTK"; ProcessingId = "P"; VersionId = "2.3.1"; if (messageSubType == System.String.Empty) { this.MSH[9] = messageType; } else { this.MSH[9] = messageType + messageDelimiters.ComponentDelimiter + messageSubType; } }
/// <summary> /// Class constructor. /// </summary> public Hl7PeerToPeerConfig() : base() { // // Constructor activities // _sessionId = 0; _messageDelimiters = new Hl7MessageDelimiters(); }
/// <summary> /// Class constructor. /// </summary> public Hl7PeerToPeerConfig() : base() { // // Constructor activities // _sessionId = 0; _messageDelimiters = new Hl7MessageDelimiters(); }
private void ValidateMessage(Hl7Message hl7RequestMessage, Hl7MessageDelimiters messageDelimiters) { try { // validate the HL7 message System.String facility = hl7RequestMessage.SendingFacility; System.String version = hl7RequestMessage.VersionId; if (_hl7ProfileStore != null) { // get the validation profile - keyed off the facility, version and messageType System.String messageType = hl7RequestMessage.MessageType; if (hl7RequestMessage.MessageSubType != System.String.Empty) { messageType += ("^" + hl7RequestMessage.MessageSubType); } System.String xmlProfile = _hl7ProfileStore.GetXmlHl7Profile(new Hl7ProfileId(facility, version, messageType)); if (_hl7ValidationContext != null) { // get the validation context System.String xmlValidationContext = _hl7ValidationContext.XmlValidationContext; if ((xmlProfile != System.String.Empty) && (xmlValidationContext != System.String.Empty) && (_nistWebServiceClient != null)) { System.String errorDescription = System.String.Empty; System.String xmlValidationResult = _nistWebServiceClient.Validate(xmlProfile, xmlValidationContext, hl7RequestMessage.ToString(messageDelimiters), false, out errorDescription); if (errorDescription != System.String.Empty) { _hl7ThreadForHl7Server.LogError(errorDescription); } NistXmlResultsParser xmlParser = new NistXmlResultsParser(xmlValidationResult); _hl7ThreadForHl7Server.UpdateValidationErrorCount(xmlParser.ErrorCount); _hl7ThreadForHl7Server.UpdateValidationWarningCount(xmlParser.WarningCount); _hl7ThreadForHl7Server.WriteXmlStringToResults(xmlParser.RemoveHeader(xmlValidationResult)); } } } } catch (System.Exception e) { System.String message = System.String.Format("NIST Validation Exception: {0} - {1}", e.Message, e.StackTrace); Console.WriteLine(message); _hl7ThreadForHl7Server.LogInformation(message); } }
/// <summary> /// Generate string representation to HL7 Message - include the end of segment character. /// </summary> /// <param name="messageDelimiters">HL7 message delimiters.</param> /// <param name="addNewLine">Add new line boolean - for display purposes.</param> /// <returns>string - HL7 ER7 format string.</returns> private System.String ToString(Hl7MessageDelimiters messageDelimiters, bool addNewLine) { System.String stringValue = System.String.Empty; // stream all the segments - ordered by sequence number and then segment index int sequenceNumber = 0; int segmentIndex = 1; bool streaming = true; while (streaming == true) { bool segmentStreamed = false; ICollection segments = _segments.Values; foreach (Hl7Segment hl7Segment in segments) { if (hl7Segment.SequenceNumber == sequenceNumber) { if (hl7Segment.SegmentId.SegmentIndex == segmentIndex) { System.String encodedStream = hl7Segment.Encode(messageDelimiters); if (encodedStream != System.String.Empty) { stringValue += (encodedStream + _EndOfSegmentChar); if (addNewLine == true) { // for display purposes only stringValue += _NewLineChar; } } segmentIndex++; segmentStreamed = true; break; } } } if (segmentStreamed == false) { if (sequenceNumber < _segments.Count) { sequenceNumber++; segmentIndex = 1; } else { streaming = false; } } } return stringValue; }
/// <summary> /// Generate string representation to HL7 Message - include the end of segment character. /// </summary> /// <param name="messageDelimiters">HL7 message delimiters.</param> /// <returns>string - HL7 ER7 format string.</returns> public System.String ToString(Hl7MessageDelimiters messageDelimiters) { return ToString(messageDelimiters, false); }
private System.String ReplaceString(System.String inputString, Hl7MessageDelimiters messageDelimiters) { // get the default message delimiters - these will have been used in the HL7 scripts, etc Hl7MessageDelimiters defaultMessageDelimiters = new Hl7MessageDelimiters(); // update the string to use the given message delimiters System.String localString1 = inputString.Replace(defaultMessageDelimiters.ComponentDelimiter, messageDelimiters.ComponentDelimiter); System.String localString2 = localString1.Replace(defaultMessageDelimiters.SubComponentDelimiter, messageDelimiters.SubComponentDelimiter); System.String outputString = localString2.Replace(defaultMessageDelimiters.RepetitionSeparator, messageDelimiters.RepetitionSeparator); return outputString; }
/// <summary> /// Encode the segment. /// </summary> /// <param name="messageDelimiters">HL7 message delimiters to use to encode the message.</param> /// <returns>String - encoded segment.</returns> public System.String Encode(Hl7MessageDelimiters messageDelimiters) { System.String segment = System.String.Empty; if (_values.Count > 1) { if (_segmentId.SegmentName == Hl7SegmentEnum.MSH) { // initialize the first fields of the MSH segment segment = (System.String)_values[0] + messageDelimiters.ToString() + messageDelimiters.FieldDelimiter; // ecode the rest of the MSH segment from the 3rd field for (int index = 3; index < _values.Count; index++) { segment += ReplaceString((System.String)_values[index], messageDelimiters);; if (index + 1 != _values.Count) { segment += messageDelimiters.FieldDelimiter; } } } else { int index = 0; foreach (System.String val in _values) { segment += ReplaceString(val, messageDelimiters); index++; if (index != _values.Count) { segment += messageDelimiters.FieldDelimiter; } } } } return segment; }
private void ValidateMessage(Hl7Message hl7ResponseMessage, Hl7MessageDelimiters messageDelimiters) { try { // validate the HL7 message System.String facility = hl7ResponseMessage.SendingFacility; System.String version = hl7ResponseMessage.VersionId; if (_hl7ProfileStore != null) { // get the validation profile - keyed off the facility, version and messageType System.String messageType = hl7ResponseMessage.MessageType; if (hl7ResponseMessage.MessageSubType != System.String.Empty) { messageType += ("^" + hl7ResponseMessage.MessageSubType); } System.String xmlProfile = _hl7ProfileStore.GetXmlHl7Profile(new Hl7ProfileId(facility, version, messageType)); if (_hl7ValidationContext != null) { // get the validation context System.String xmlValidationContext = _hl7ValidationContext.XmlValidationContext; if ((xmlProfile != System.String.Empty) && (xmlValidationContext != System.String.Empty) && (_nistWebServiceClient != null)) { System.String errorDescription = System.String.Empty; System.String xmlValidationResult = _nistWebServiceClient.Validate(xmlProfile, xmlValidationContext, hl7ResponseMessage.ToString(messageDelimiters), false, out errorDescription); if (errorDescription != System.String.Empty) { _hl7ThreadForHl7Client.LogError(errorDescription); } NistXmlResultsParser xmlParser = new NistXmlResultsParser(xmlValidationResult); _hl7ThreadForHl7Client.UpdateValidationErrorCount(xmlParser.ErrorCount); _hl7ThreadForHl7Client.UpdateValidationWarningCount(xmlParser.WarningCount); _hl7ThreadForHl7Client.WriteXmlStringToResults(xmlParser.RemoveHeader(xmlValidationResult)); } } } } catch (System.Exception e) { System.String message = System.String.Format("NIST Validation Exception: {0} - {1}", e.Message, e.StackTrace); Console.WriteLine(message); _hl7ThreadForHl7Client.LogInformation(message); } }
/// <summary> /// Send an HL7 message over the connected network stream. /// </summary> /// <param name="hl7Message">HL7 message to encode.</param> /// <param name="messageDelimiters">HL7 message delimiters.</param> /// <returns>bool - successful sent = true else false.</returns> public bool SendMessage(Hl7Message hl7Message, Hl7MessageDelimiters messageDelimiters) { if (_networkStream == null) return false; // set the read / write timeouts for this stream - zero means no timeout. if (_readTimeout != 0) { _networkStream.ReadTimeout = _readTimeout; } if (_writeTimeout != 0) { _networkStream.WriteTimeout = _writeTimeout; } // write the start of message character _networkStream.WriteByte((byte)_StartOfMessageChar); // stream all the segments - ordered by sequence number and then segment index int sequenceNumber = 0; int segmentIndex = 1; bool streaming = true; while (streaming == true) { bool segmentStreamed = false; ICollection segments = hl7Message.Segments.Values; foreach (Hl7Segment hl7Segment in segments) { if (hl7Segment.SequenceNumber == sequenceNumber) { if (hl7Segment.SegmentId.SegmentIndex == segmentIndex) { System.String encodedStream = hl7Segment.Encode(messageDelimiters); if (encodedStream != System.String.Empty) { byte[] buffer = new byte[encodedStream.Length]; for (int j = 0; j < encodedStream.Length; j++) { buffer[j] = (byte) encodedStream[j]; } // write the segment _networkStream.Write(buffer, 0, encodedStream.Length); // write the end of segment character _networkStream.WriteByte((byte)_EndOfSegmentChar); } segmentIndex++; segmentStreamed = true; break; } } } if (segmentStreamed == false) { if (sequenceNumber < hl7Message.Segments.Count) { sequenceNumber++; segmentIndex = 1; } else { streaming = false; } } } // write the end of message characters _networkStream.WriteByte((byte)_EndOfMessageChar1); _networkStream.WriteByte((byte)_EndOfMessageChar2); _networkStream.Flush(); return true; }
/// <summary> /// Receive an HL7 message over the connected network stream. /// </summary> /// <param name="messageDelimiters">Initial HL7 message delimiters - updated to actual delimters during method.</param> /// <returns>Correctly instantiated HL7 message.</returns> public Hl7Message ReceiveMessage(out Hl7MessageDelimiters messageDelimiters) { // initialize the message delimiters to the default values messageDelimiters = new Hl7MessageDelimiters(); Hl7Message hl7Message = new Hl7Message(); if (_networkStream == null) return null; // set the read / write timeouts for this stream - zero means no timeout. if (_readTimeout != 0) { _networkStream.ReadTimeout = _readTimeout; } if (_writeTimeout != 0) { _networkStream.WriteTimeout = _writeTimeout; } // initialise the segment content System.String rxSegment = System.String.Empty; // initialise the MLLP state MllpStateEnum mllpState = MllpStateEnum.WaitingForStartOfMessageChar; // loop waiting for the end of message character while (mllpState != MllpStateEnum.DoneWaiting) { // check if data is available on network try { // get the next character from the stream int rxCode = _networkStream.ReadByte(); if (rxCode < 0) { return null; } char rxChar = (char) rxCode; // switch on MLLP state switch(mllpState) { case MllpStateEnum.WaitingForStartOfMessageChar: // check if we have got the SOM if (rxChar == _StartOfMessageChar) { // reset the segment rxSegment = System.String.Empty; // change state to waiting for end of segment mllpState = MllpStateEnum.WaitingForEndOfSegmentChar; } else { Console.WriteLine("HL7 - MLLP: Waiting for SOM - got {0}...", rxChar); } break; case MllpStateEnum.WaitingForEndOfSegmentChar: // check if we have got the end of segment if (rxChar == _EndOfSegmentChar) { // check if we have the MSH segment // - we need to get the message delimiters if (rxSegment.StartsWith("MSH") == true) { // set the message delimiters to the values received // - we assume that the MSH segment is formatted properly at least in the first few bytes messageDelimiters = new Hl7MessageDelimiters(rxSegment.Substring(3,5)); } // segment is complete Hl7Segment segment = new Hl7Segment(); segment.Decode(rxSegment, messageDelimiters); // add the segment to the HL7 message hl7Message.AddSegment(segment); // reset the segment rxSegment = System.String.Empty; } else if (rxChar == _EndOfMessageChar1) { // we have the first end of message - that's OK // check if any characters have been received since the last end of segment if (rxSegment == System.String.Empty) { // change state to waiting for second end of message mllpState = MllpStateEnum.WaitingForEndOfMessageChar; } else { Console.WriteLine("HL7 - MLLP: First EOM does not immediately follow an EOS"); return null; } } else { // save the received character in the current segment rxSegment += rxChar; } break; case MllpStateEnum.WaitingForEndOfMessageChar: // check if we have got the second end of message if (rxChar == _EndOfMessageChar2) { // message is complete mllpState = MllpStateEnum.DoneWaiting; } else { Console.WriteLine("HL7 - MLLP: Second EOM does not immediately follow first EOM"); return null; } break; default: break; } } catch (System.Exception e) { Console.WriteLine("HL7 - MLLP: ReceiveMessage() Exception: {0}", e.Message); return null; } } // return the correct instantiation of the received HL7 message return Hl7MessageFactory.CreateHl7Message(hl7Message, messageDelimiters); }
private void ProcessTrigger(Hl7Trigger trigger) { _hl7Mllp = new Hl7Mllp(); // get the next transaction number - needed to sort the // transactions correctly int transactionNumber = TransactionNumber.GetNextTransactionNumber(); System.String message = System.String.Format("HL7 Client thread - connecting to \"{0}\" on port {1}...", _config.ToActorIpAddress, _config.PortNumber); _hl7ThreadForHl7Client.LogInformation(message); if (_hl7Mllp.Connect(_config.ToActorIpAddress, _config.PortNumber)) { Hl7Message hl7RequestMessage = trigger.Trigger; // Set the sending and receiving applications hl7RequestMessage.SendingApplication = _config.FromActorAeTitle; hl7RequestMessage.ReceivingApplication = _config.ToActorAeTitle; // Add the control id and date/time of message hl7RequestMessage.MessageControlId = _messageControlId.ToString(); _messageControlId++; hl7RequestMessage.DateTimeOfMessage = System.DateTime.Now.ToString("yyyyMMddhhmmss", System.Globalization.CultureInfo.InvariantCulture); // get initial HL7 message delimiters from the config Hl7MessageDelimiters messageDelimiters = _config.MessageDelimiters; System.String messageType = hl7RequestMessage.Value(Hl7SegmentEnum.MSH, 9); _hl7ThreadForHl7Client.LogInformation(System.String.Format("HL7 Client thread - send message \"{0}\".", messageType)); _hl7ThreadForHl7Client.LogInformation(hl7RequestMessage.ToString(messageDelimiters)); if (_hl7Mllp.SendMessage(hl7RequestMessage, messageDelimiters) == true) { Hl7Message hl7ResponseMessage = _hl7Mllp.ReceiveMessage(out messageDelimiters); if (hl7ResponseMessage != null) { messageType = hl7ResponseMessage.Value(Hl7SegmentEnum.MSH, 9); _hl7ThreadForHl7Client.LogInformation(System.String.Format("HL7 Client thread - received message \"{0}\".", messageType)); _hl7ThreadForHl7Client.LogInformation(hl7ResponseMessage.ToString(messageDelimiters)); // Validate the message if (_config.AutoValidate == true) { ValidateMessage(hl7ResponseMessage, messageDelimiters); } // save the transaction Hl7Transaction transaction = new Hl7Transaction(TransactionNameEnum.RAD_1, TransactionDirectionEnum.TransactionSent); transaction.Request = hl7RequestMessage; transaction.Response = hl7ResponseMessage; ActorsTransaction actorsTransaction = new ActorsTransaction(transactionNumber, ActorName, // from actor ParentActor.ActorName, // to actor transaction, _hl7ThreadForHl7Client.Options.ResultsFileNameOnly, _hl7ThreadForHl7Client.Options.ResultsFullFileName, (uint)_hl7ThreadForHl7Client.NrErrors, (uint)_hl7ThreadForHl7Client.NrWarnings); // save the transaction in the Actor log ParentActor.ActorsTransactionLog.Add(actorsTransaction); // publish the transaction event to any interested parties PublishTransactionAvailableEvent(ActorName, actorsTransaction); } } _hl7Mllp.Stop(); _hl7ThreadForHl7Client.StopResultsGathering(); _hl7ThreadForHl7Client.StartResultsGathering(); } if (_awaitCompletion == true) { _semaphore.Signal(); } }
// // - Methods - // /// <summary> /// Decode a Hl7Message object from a given stream. /// </summary> /// <param name="stream">The stream.</param> /// <returns>The decoded Hl7Message.</returns> internal Hl7Message Decode(System.IO.Stream stream) { Hl7Message hl7Message = new Hl7Message(); // initialize the message delimiters to the default values _messageDelimiters = new Hl7MessageDelimiters(); // initialise the segment content System.String rxSegment = System.String.Empty; // read the first character from the stream to determine if the MLLP is used int rxCode = stream.ReadByte(); if (rxCode < 0) { throw new System.Exception("Incomplete HL7 stream."); } stream.Seek(0, System.IO.SeekOrigin.Begin); // initialise the MLLP state MllpStateEnum mllpState = MllpStateEnum.MllpNotUsed; if ((char)rxCode == _StartOfMessageChar) { // SOM read - use the MLLP protocol mllpState = MllpStateEnum.WaitingForStartOfMessageChar; } // loop waiting for the end of message character while (_continueReading) { // get the next character from the stream rxCode = stream.ReadByte(); if (rxCode < 0) { // end of stream reached when not using the MLLP // - check if there is any data left in the rxSegment if ((rxSegment != System.String.Empty) && (mllpState == MllpStateEnum.MllpNotUsed)) { // segment is complete Hl7Segment segment = new Hl7Segment(); segment.Decode(rxSegment, _messageDelimiters); // add the segment to the HL7 message hl7Message.AddSegment(segment); } // message is complete _continueReading = false; break; } char rxChar = (char) rxCode; // switch on MLLP state switch(mllpState) { case MllpStateEnum.MllpNotUsed: // check if we have got the end of segment if (rxChar == _EndOfSegmentChar) { // check if we have the MSH segment // - we need to get the message delimiters if (rxSegment.StartsWith("MSH") == true) { // set the message delimiters to the values received // - we assume that the MSH segment is formatted properly at least in the first few bytes _messageDelimiters = new Hl7MessageDelimiters(rxSegment.Substring(3,5)); } // segment is complete Hl7Segment segment = new Hl7Segment(); segment.Decode(rxSegment, _messageDelimiters); // add the segment to the HL7 message hl7Message.AddSegment(segment); // reset the segment rxSegment = System.String.Empty; } else if (rxChar == _NewLineChar) { // ignore the line feed character } else { // save the received character in the current segment rxSegment += rxChar; } break; case MllpStateEnum.WaitingForStartOfMessageChar: // check if we have got the SOM if (rxChar == _StartOfMessageChar) { // reset the segment rxSegment = System.String.Empty; // change state to waiting for end of segment mllpState = MllpStateEnum.WaitingForEndOfSegmentChar; } else { Console.WriteLine("HL7 - MLLP: Waiting for SOM - got {0}...", rxChar); } break; case MllpStateEnum.WaitingForEndOfSegmentChar: // check if we have got the end of segment if (rxChar == _EndOfSegmentChar) { // check if we have the MSH segment // - we need to get the message delimiters if (rxSegment.StartsWith("MSH") == true) { // set the message delimiters to the values received // - we assume that the MSH segment is formatted properly at least in the first few bytes _messageDelimiters = new Hl7MessageDelimiters(rxSegment.Substring(3,5)); } // segment is complete Hl7Segment segment = new Hl7Segment(); segment.Decode(rxSegment, _messageDelimiters); // add the segment to the HL7 message hl7Message.AddSegment(segment); // reset the segment rxSegment = System.String.Empty; } else if (rxChar == _EndOfMessageChar1) { // we have the first end of message - that's OK // check if any characters have been received since the last end of segment if (rxSegment == System.String.Empty) { // change state to waiting for second end of message mllpState = MllpStateEnum.WaitingForEndOfMessageChar; } else { Console.WriteLine("HL7 - MLLP: First EOM does not immediately follow an EOS"); return null; } } else { // save the received character in the current segment rxSegment += rxChar; } break; case MllpStateEnum.WaitingForEndOfMessageChar: // check if we have got the second end of message if (rxChar == _EndOfMessageChar2) { // message is complete _continueReading = false; } else { Console.WriteLine("HL7 - MLLP: Second EOM does not immediately follow first EOM"); return null; } break; default: break; } } // return the correct instantiation of the received HL7 message return Hl7MessageFactory.CreateHl7Message(hl7Message, _messageDelimiters); }
/// <summary> /// Create a correctly typed HL7 message instance based on the incoming Hl7 message. /// </summary> /// <param name="inHl7Message">Incoming HL7 message.</param> /// <param name="messageDelimiters">HL7 message delimiters.</param> /// <returns>Correctly typed HL7 message instance.</returns> public static Hl7Message CreateHl7Message(Hl7Message inHl7Message, Hl7MessageDelimiters messageDelimiters) { Hl7SegmentId segmentId = new Hl7SegmentId(Hl7SegmentEnum.MSH); Hl7Segment mshSegment = (Hl7Segment)inHl7Message.Segments[segmentId.Id]; // can not determine what kind of message we have - so return the inHl7Message if (mshSegment == null) { return inHl7Message; } System.String messageType = mshSegment[9]; Hl7Message hl7Message = null; // check for ACK message if (messageType == "ACK") { // now try to get the ORC segment segmentId = new Hl7SegmentId(Hl7SegmentEnum.ORC); Hl7Segment orcSegment = (Hl7Segment)inHl7Message.Segments[segmentId.Id]; if (orcSegment != null) { hl7Message = new OrrMessage(); } else { hl7Message = new AckMessage(); } } else { System.String []messageTypeComponent = new System.String[3]; messageTypeComponent = messageType.Split(messageDelimiters.ComponentDelimiter[0]); System.String messageMainType = System.String.Empty; if (messageTypeComponent.Length > 0) { messageMainType = messageTypeComponent[0]; } switch (messageMainType) { case "ADR" : // ADR message hl7Message = new AdrMessage(); break; case "ADT" : // ADT message hl7Message = new AdtMessage(); break; case "ORM" : // ORM message hl7Message = new OrmMessage(); break; case "ORU" : // ORU message hl7Message = new OruMessage(); break; case "QRY" : // QRY message hl7Message = new QryMessage(); break; default: // do not know what kind of HL7 message this is - simply return it return inHl7Message; } } // add the segments from the inMessage to the new hl7Message ICollection segments = inHl7Message.Segments.Values; foreach (Hl7Segment segment in segments) { hl7Message.CopySegment(segment); } return hl7Message; }
/// <summary> /// Send an HL7 message over the connected network stream. /// </summary> /// <param name="hl7Message">HL7 message to encode.</param> /// <param name="messageDelimiters">HL7 message delimiters.</param> /// <returns>bool - successful sent = true else false.</returns> public bool SendMessage(Hl7Message hl7Message, Hl7MessageDelimiters messageDelimiters) { if (_networkStream == null) { return(false); } // set the read / write timeouts for this stream - zero means no timeout. if (_readTimeout != 0) { _networkStream.ReadTimeout = _readTimeout; } if (_writeTimeout != 0) { _networkStream.WriteTimeout = _writeTimeout; } // write the start of message character _networkStream.WriteByte((byte)_StartOfMessageChar); // stream all the segments - ordered by sequence number and then segment index int sequenceNumber = 0; int segmentIndex = 1; bool streaming = true; while (streaming == true) { bool segmentStreamed = false; ICollection segments = hl7Message.Segments.Values; foreach (Hl7Segment hl7Segment in segments) { if (hl7Segment.SequenceNumber == sequenceNumber) { if (hl7Segment.SegmentId.SegmentIndex == segmentIndex) { System.String encodedStream = hl7Segment.Encode(messageDelimiters); if (encodedStream != System.String.Empty) { byte[] buffer = new byte[encodedStream.Length]; for (int j = 0; j < encodedStream.Length; j++) { buffer[j] = (byte)encodedStream[j]; } // write the segment _networkStream.Write(buffer, 0, encodedStream.Length); // write the end of segment character _networkStream.WriteByte((byte)_EndOfSegmentChar); } segmentIndex++; segmentStreamed = true; break; } } } if (segmentStreamed == false) { if (sequenceNumber < hl7Message.Segments.Count) { sequenceNumber++; segmentIndex = 1; } else { streaming = false; } } } // write the end of message characters _networkStream.WriteByte((byte)_EndOfMessageChar1); _networkStream.WriteByte((byte)_EndOfMessageChar2); _networkStream.Flush(); return(true); }
/// <summary> /// Decode the segment. The HL7 message delimiters has been set to the correct value before calling this method. /// </summary> /// <param name="segmentString">Encoded segment string.</param> /// <param name="messageDelimiters">HL7 message delimiters to use to encode the message.</param> public void Decode(System.String segmentString, Hl7MessageDelimiters messageDelimiters) { int index = 0; System.String val = System.String.Empty; int i = 0; bool isVal = false; while (i < segmentString.Length) { if (segmentString.Substring(i,1) == messageDelimiters.FieldDelimiter) { _values.Insert(index, val); index++; if ((index == 1) && ((System.String)_values[0] == "MSH")) { // special insert for the field delimiter itself. _values.Insert(index, messageDelimiters.FieldDelimiter); index++; } val = System.String.Empty; isVal = false; } else { val += segmentString[i]; isVal = true; } i++; } if (isVal == true) { _values.Insert(index, val); } if (_values.Count > 0) { // use segment index 0 here - the correct value will be determined when the segment is added to the message _segmentId = new Hl7SegmentId(SegmentNames.NameEnum((System.String)_values[0]), 0); } }
/// <summary> /// Receive an HL7 message over the connected network stream. /// </summary> /// <param name="messageDelimiters">Initial HL7 message delimiters - updated to actual delimters during method.</param> /// <returns>Correctly instantiated HL7 message.</returns> public Hl7Message ReceiveMessage(out Hl7MessageDelimiters messageDelimiters) { // initialize the message delimiters to the default values messageDelimiters = new Hl7MessageDelimiters(); Hl7Message hl7Message = new Hl7Message(); if (_networkStream == null) { return(null); } // set the read / write timeouts for this stream - zero means no timeout. if (_readTimeout != 0) { _networkStream.ReadTimeout = _readTimeout; } if (_writeTimeout != 0) { _networkStream.WriteTimeout = _writeTimeout; } // initialise the segment content System.String rxSegment = System.String.Empty; // initialise the MLLP state MllpStateEnum mllpState = MllpStateEnum.WaitingForStartOfMessageChar; // loop waiting for the end of message character while (mllpState != MllpStateEnum.DoneWaiting) { // check if data is available on network try { // get the next character from the stream int rxCode = _networkStream.ReadByte(); if (rxCode < 0) { return(null); } char rxChar = (char)rxCode; // switch on MLLP state switch (mllpState) { case MllpStateEnum.WaitingForStartOfMessageChar: // check if we have got the SOM if (rxChar == _StartOfMessageChar) { // reset the segment rxSegment = System.String.Empty; // change state to waiting for end of segment mllpState = MllpStateEnum.WaitingForEndOfSegmentChar; } else { Console.WriteLine("HL7 - MLLP: Waiting for SOM - got {0}...", rxChar); } break; case MllpStateEnum.WaitingForEndOfSegmentChar: // check if we have got the end of segment if (rxChar == _EndOfSegmentChar) { // check if we have the MSH segment // - we need to get the message delimiters if (rxSegment.StartsWith("MSH") == true) { // set the message delimiters to the values received // - we assume that the MSH segment is formatted properly at least in the first few bytes messageDelimiters = new Hl7MessageDelimiters(rxSegment.Substring(3, 5)); } // segment is complete Hl7Segment segment = new Hl7Segment(); segment.Decode(rxSegment, messageDelimiters); // add the segment to the HL7 message hl7Message.AddSegment(segment); // reset the segment rxSegment = System.String.Empty; } else if (rxChar == _EndOfMessageChar1) { // we have the first end of message - that's OK // check if any characters have been received since the last end of segment if (rxSegment == System.String.Empty) { // change state to waiting for second end of message mllpState = MllpStateEnum.WaitingForEndOfMessageChar; } else { Console.WriteLine("HL7 - MLLP: First EOM does not immediately follow an EOS"); return(null); } } else { // save the received character in the current segment rxSegment += rxChar; } break; case MllpStateEnum.WaitingForEndOfMessageChar: // check if we have got the second end of message if (rxChar == _EndOfMessageChar2) { // message is complete mllpState = MllpStateEnum.DoneWaiting; } else { Console.WriteLine("HL7 - MLLP: Second EOM does not immediately follow first EOM"); return(null); } break; default: break; } } catch (System.Exception e) { Console.WriteLine("HL7 - MLLP: ReceiveMessage() Exception: {0}", e.Message); return(null); } } // return the correct instantiation of the received HL7 message return(Hl7MessageFactory.CreateHl7Message(hl7Message, messageDelimiters)); }
/// <summary> /// Process Hl7 requests and responses. /// </summary> public void ProcessMessages() { _hl7Mllp = new Hl7Mllp(); for (;;) { System.String message = System.String.Format("Listening for incoming HL7 connection on port {0}...", _config.PortNumber); _hl7ThreadForHl7Server.LogInformation(message); try { // listen for a connection _hl7Mllp.Listen(_config.PortNumber); for (;;) { // accept the connection - only one at a time _hl7Mllp.Accept(); // the message delimiters will be filled in by the ReceiveMessage method Hl7MessageDelimiters messageDelimiters = null; // receive an HL7 message Hl7Message hl7RequestMessage = _hl7Mllp.ReceiveMessage(out messageDelimiters); if (hl7RequestMessage != null) { System.String messageType = hl7RequestMessage.Value(Hl7SegmentEnum.MSH, 9); message = System.String.Format("HL7 Server thread - received message \"{0}\".", messageType); _hl7ThreadForHl7Server.LogInformation(message); _hl7ThreadForHl7Server.LogInformation(hl7RequestMessage.ToString(messageDelimiters)); // Validate the message if (_config.AutoValidate == true) { ValidateMessage(hl7RequestMessage, messageDelimiters); } // call the message handler to get a response Hl7Message hl7ResponseMessage = MessageHandler(hl7RequestMessage); // copy some fields from the request hl7ResponseMessage.SendingApplication = hl7RequestMessage.ReceivingApplication; hl7ResponseMessage.SendingFacility = hl7RequestMessage.ReceivingFacility; hl7ResponseMessage.ReceivingApplication = hl7RequestMessage.SendingApplication; hl7ResponseMessage.ReceivingFacility = hl7RequestMessage.SendingFacility; hl7ResponseMessage.MessageControlId = hl7RequestMessage.MessageControlId; // set the date/time of message hl7ResponseMessage.DateTimeOfMessage = System.DateTime.Now.ToString("yyyyMMddhhmmss", System.Globalization.CultureInfo.InvariantCulture); // send the response _hl7Mllp.SendMessage(hl7ResponseMessage, messageDelimiters); messageType = hl7ResponseMessage.Value(Hl7SegmentEnum.MSH, 9); message = System.String.Format("HL7 Server thread - sent message \"{0}\".", messageType); _hl7ThreadForHl7Server.LogInformation(message); _hl7ThreadForHl7Server.LogInformation(hl7ResponseMessage.ToString(messageDelimiters)); // get the next transaction number - needed to sort the // transactions correctly int transactionNumber = TransactionNumber.GetNextTransactionNumber(); // save the transaction Hl7Transaction transaction = new Hl7Transaction(TransactionNameEnum.RAD_1, TransactionDirectionEnum.TransactionReceived); transaction.Request = hl7RequestMessage; transaction.Response = hl7ResponseMessage; _hl7ThreadForHl7Server.LogInformation(String.Format("{0} - received Hl7 event from {1}", ParentActor.ActorName, ActorName)); ActorsTransaction actorsTransaction = new ActorsTransaction(transactionNumber, ActorName, // from actor ParentActor.ActorName, // to actor transaction, _hl7ThreadForHl7Server.Options.ResultsFileNameOnly, _hl7ThreadForHl7Server.Options.ResultsFullFileName, (uint)_hl7ThreadForHl7Server.NrErrors, (uint)_hl7ThreadForHl7Server.NrWarnings); // save the transaction in the Actor log ParentActor.ActorsTransactionLog.Add(actorsTransaction); // publish the transaction event to any interested parties PublishTransactionAvailableEvent(ActorName, actorsTransaction); } _hl7Mllp.Close(); _hl7ThreadForHl7Server.StopResultsGathering(); _hl7ThreadForHl7Server.StartResultsGathering(); } } catch { // System.Net.Sockets.Socket.Accept() exception thrown when the server is stopped by closing the listen socket. break; } } }