/// <param name="message">a parsed message to validate (note that MSH-9-1 and MSH-9-2 must be valued)
		/// </param>
		/// <returns> true if the message is OK
		/// </returns>
		/// <throws>  HL7Exception if there is at least one error and this validator is set to fail on errors </throws>
		public virtual bool validate(Message message)
		{
			Terser t = new Terser(message);
			NuGenMessageRule[] rules = myContext.getMessageRules(message.Version, t.get_Renamed("MSH-9-1"), t.get_Renamed("MSH-9-2"));
			
			NuGenValidationException toThrow = null;
			bool result = true;
			for (int i = 0; i < rules.Length; i++)
			{
				NuGenValidationException[] ex = rules[i].test(message);
				for (int j = 0; j < ex.Length; j++)
				{
					result = false;
					if (failOnError && toThrow == null)
					{
						toThrow = ex[j];
					}
				}
			}
			
			if (toThrow != null)
			{
				throw new NuGenHL7Exception("Invalid message", toThrow);
			}
			
			return result;
		}
Example #2
0
        /// <seealso cref="Genetibase.NuGenHL7.protocol.Initiator.sendAndReceive(Genetibase.NuGenHL7.model.Message)">
        /// </seealso>
        public virtual Message sendAndReceive(Message theMessage)
        {
            Terser t = new Terser(theMessage);

            System.String appAckNeeded = t.get_Renamed("/MSH-16");
            System.String msgId        = t.get_Renamed("/MSH-10");

            System.String messageText = Parser.encode(theMessage);
            System.Collections.IDictionary metadata    = getMetadata(theMessage);
            NuGenTransportable             out_Renamed = new NuGenTransportableImpl(messageText, metadata);

            if (needAck(appAckNeeded))
            {
                myProcessor.reserve(msgId, ReceiveTimeout);
            }

            myProcessor.send(out_Renamed, MaxRetries, RetryInterval);

            Message in_Renamed = null;

            if (needAck(appAckNeeded))
            {
                NuGenTransportable received = myProcessor.receive(msgId, ReceiveTimeout);
                if (received != null && received.Message != null)
                {
                    in_Renamed = Parser.parse(received.Message);
                }
            }

            return(in_Renamed);
        }
        /// <summary> Returns the Applications that has been registered to handle
        /// messages of the type and trigger event of the given message, or null if
        /// there are none.
        /// </summary>
        private NuGenApplication getMatchingApplication(Message message)
        {
            Terser t = new Terser(message);

            System.String messageType  = t.get_Renamed("/MSH-9-1");
            System.String triggerEvent = t.get_Renamed("/MSH-9-2");
            return(this.getMatchingApplication(messageType, triggerEvent));
        }
Example #4
0
            public virtual void  Run()
            {
                try
                {
                    //get message ID
                    System.String ID          = MessageIDGenerator.Instance.NewID;
                    Message       out_Renamed = parser.parse(outText);
                    Terser        tOut        = new Terser(out_Renamed);
                    tOut.set_Renamed("/MSH-10", ID);

                    //send, get response
                    Message in_Renamed = initiator.sendAndReceive(out_Renamed);

                    //get ACK ID
                    Terser        tIn   = new Terser(in_Renamed);
                    System.String ackID = tIn.get_Renamed("/MSA-2");
                    if (ID.Equals(ackID))
                    {
                        System.Console.Out.WriteLine("OK - ack ID matches");
                    }
                    else
                    {
                        throw new System.SystemException("Ack ID for message " + ID + " is " + ackID);
                    }
                }
                catch (System.Exception e)
                {
                    SupportClass.WriteStackTrace(e, Console.Error);
                }
            }
Example #5
0
        /// <param name="message">a parsed message to validate (note that MSH-9-1 and MSH-9-2 must be valued)
        /// </param>
        /// <returns> true if the message is OK
        /// </returns>
        /// <throws>  HL7Exception if there is at least one error and this validator is set to fail on errors </throws>
        public virtual bool validate(Message message)
        {
            Terser t = new Terser(message);

            NuGenMessageRule[] rules = myContext.getMessageRules(message.Version, t.get_Renamed("MSH-9-1"), t.get_Renamed("MSH-9-2"));

            NuGenValidationException toThrow = null;
            bool result = true;

            for (int i = 0; i < rules.Length; i++)
            {
                NuGenValidationException[] ex = rules[i].test(message);
                for (int j = 0; j < ex.Length; j++)
                {
                    result = false;
                    if (failOnError && toThrow == null)
                    {
                        toThrow = ex[j];
                    }
                }
            }

            if (toThrow != null)
            {
                throw new NuGenHL7Exception("Invalid message", toThrow);
            }

            return(result);
        }
Example #6
0
        /// <summary> Formats a Message object into an HL7 message string using this parser's
        /// default encoding ("VB").
        /// </summary>
        /// <throws>  HL7Exception if the data fields in the message do not permit encoding </throws>
        /// <summary>      (e.g. required fields are null)
        /// </summary>
        protected internal override System.String doEncode(Message source)
        {
            //get encoding characters ...
            Segment msh = (Segment)source.get_Renamed("MSH");

            System.String fieldSepString = Terser.get_Renamed(msh, 1, 0, 1, 1);

            if (fieldSepString == null)
            {
                throw new NuGenHL7Exception("Can't encode message: MSH-1 (field separator) is missing");
            }

            char fieldSep = '|';

            if (fieldSepString != null && fieldSepString.Length > 0)
            {
                fieldSep = fieldSepString[0];
            }

            System.String encCharString = Terser.get_Renamed(msh, 2, 0, 1, 1);

            if (encCharString == null)
            {
                throw new NuGenHL7Exception("Can't encode message: MSH-2 (encoding characters) is missing");
            }

            if (encCharString.Length != 4)
            {
                throw new NuGenHL7Exception("Encoding characters '" + encCharString + "' invalid -- must be 4 characters", NuGenHL7Exception.DATA_TYPE_ERROR);
            }
            NuGenEncodingCharacters en = new NuGenEncodingCharacters(fieldSep, encCharString);

            //pass down to group encoding method which will operate recursively on children ...
            return(encode((Group)source, en));
        }
			public virtual void  Run()
			{
				try
				{
					//get message ID
					System.String ID = MessageIDGenerator.Instance.NewID;
					Message out_Renamed = parser.parse(outText);
					Terser tOut = new Terser(out_Renamed);
					tOut.set_Renamed("/MSH-10", ID);
					
					//send, get response
					Message in_Renamed = initiator.sendAndReceive(out_Renamed);
					
					//get ACK ID
					Terser tIn = new Terser(in_Renamed);
					System.String ackID = tIn.get_Renamed("/MSA-2");
					if (ID.Equals(ackID))
					{
						System.Console.Out.WriteLine("OK - ack ID matches");
					}
					else
					{
						throw new System.SystemException("Ack ID for message " + ID + " is " + ackID);
					}
				}
				catch (System.Exception e)
				{
					SupportClass.WriteStackTrace(e, Console.Error);
				}
			}
        private System.String[] getDeclaredProfileIDs(Message theMessage)
        {
            Terser t      = new Terser(theMessage);
            bool   noMore = false;
            int    c      = 0;

            System.Collections.ArrayList declaredProfiles = new System.Collections.ArrayList(8);
            while (!noMore)
            {
                System.String path  = "MSH-21(" + c++ + ")";
                System.String idRep = t.get_Renamed(path);
                //FIXME fails if empty rep precedes full rep ... should add getAll() to Terser and use that
                if (idRep == null || idRep.Equals(""))
                {
                    noMore = true;
                }
                else
                {
                    declaredProfiles.Add(idRep);
                }
            }

            String[] retVal = new String[declaredProfiles.Count];
            declaredProfiles.CopyTo(retVal);

            return(retVal);
        }
Example #9
0
        /// <summary> Sends a message to a responder system, receives the reply, and
        /// returns the reply as a Message object.  This method is thread-safe - multiple
        /// threads can share an Initiator and call this method.  Responses are returned to
        /// the calling thread on the basis of message ID.
        /// </summary>
        public virtual Message sendAndReceive(Message out_Renamed)
        {
            if (out_Renamed == null)
            {
                throw new NuGenHL7Exception("Can't encode null message", NuGenHL7Exception.REQUIRED_FIELD_MISSING);
            }

            //register message with response Receiver(s) (by message ID)
            Terser t = new Terser(out_Renamed);

            System.String       messID = t.get_Renamed("/MSH-10");
            NuGenMessageReceipt mr     = this.conn.reserveResponse(messID);

            //log and send message
            System.String outbound = conn.Parser.encode(out_Renamed);

            try
            {
                this.conn.SendWriter.writeMessage(outbound);
            }
            catch (System.IO.IOException e)
            {
                conn.close();
                throw e;
            }

            //wait for response
            bool    done      = false;
            Message response  = null;
            long    startTime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;

            while (!done)
            {
                lock (mr)
                {
                    try
                    {
                        System.Threading.Monitor.Wait(mr, TimeSpan.FromMilliseconds(500));                         //if it comes, notifyAll() will be called
                    }
                    catch (System.Threading.ThreadInterruptedException)
                    {
                    }

                    if (mr.Message != null)
                    {
                        //get message from receipt
                        System.String inbound = mr.Message;

                        //parse message
                        response = conn.Parser.parse(inbound);
                        done     = true;
                    }

                    //if ((System.DateTime.Now.Ticks - 621355968000000000) / 10000 > startTime + timeoutMillis)
                    //throw new HL7Exception("Timeout waiting for response to message with control ID '" + messID);
                }
            }

            return(response);
        }
Example #10
0
        /// <summary> Logs the given exception and creates an error message to send to the
        /// remote system.
        ///
        /// </summary>
        /// <param name="encoding">The encoding for the error message. If <code>null</code>, uses default encoding
        /// </param>
        public static System.String logAndMakeErrorMessage(System.Exception e, Segment inHeader, Parser p, System.String encoding)
        {
            // create error message ...
            System.String errorMessage = null;
            try
            {
                Message out_Renamed = NuGenDefaultApplication.makeACK(inHeader);
                Terser  t           = new Terser(out_Renamed);

                //copy required data from incoming message ...
                try
                {
                    t.set_Renamed("/MSH-10", MessageIDGenerator.Instance.NewID);
                }
                catch (System.IO.IOException ioe)
                {
                    throw new NuGenHL7Exception("Problem creating error message ID: " + ioe.Message);
                }

                //populate MSA ...
                t.set_Renamed("/MSA-1", "AE");                 //should this come from HL7Exception constructor?
                t.set_Renamed("/MSA-2", Terser.get_Renamed(inHeader, 10, 0, 1, 1));
                System.String excepMessage = e.Message;
                if (excepMessage != null)
                {
                    t.set_Renamed("/MSA-3", excepMessage.Substring(0, (System.Math.Min(80, excepMessage.Length)) - (0)));
                }

                /* Some earlier ACKs don't have ERRs, but I think we'll change this within HAPI
                 * so that there is a single ACK for each version (with an ERR). */
                //see if it's an HL7Exception (so we can get specific information) ...
                if (e.GetType().Equals(typeof(NuGenHL7Exception)))
                {
                    Segment err = (Segment)out_Renamed.get_Renamed("ERR");
                    ((NuGenHL7Exception)e).populate(err);
                }
                else
                {
                    t.set_Renamed("/ERR-1-4-1", "207");
                    t.set_Renamed("/ERR-1-4-2", "Application Internal Error");
                    t.set_Renamed("/ERR-1-4-3", "HL70357");
                }

                if (encoding != null)
                {
                    errorMessage = p.encode(out_Renamed, encoding);
                }
                else
                {
                    errorMessage = p.encode(out_Renamed);
                }
            }
            catch (System.IO.IOException ioe)
            {
                throw new NuGenHL7Exception("IOException creating error response message: " + ioe.Message, NuGenHL7Exception.APPLICATION_INTERNAL_ERROR);
            }
            return(errorMessage);
        }
		/// <param name="theMessage">a message from which to extract fields
		/// </param>
		/// <param name="theTerserPaths">a list of paths to desired fields, in the 
		/// form required by <code>Terser</code>.  
		/// </param>
		/// <returns> a Map from Terser paths to field values 
		/// </returns>
		public static System.Collections.IDictionary getFields(Message theMessage, System.Collections.IList theTerserPaths)
		{
			System.Collections.IDictionary fields = new System.Collections.Hashtable();
			Terser terser = new Terser(theMessage);
			for (int i = 0; i < theTerserPaths.Count; i++)
			{
				System.String path = (System.String) theTerserPaths[i];
				System.String fieldValue = terser.get_Renamed(path);
				fields[path] = fieldValue;
			}
			return fields;
		}
Example #12
0
        /// <param name="theMessage">a message from which to extract fields
        /// </param>
        /// <param name="theTerserPaths">a list of paths to desired fields, in the
        /// form required by <code>Terser</code>.
        /// </param>
        /// <returns> a Map from Terser paths to field values
        /// </returns>
        public static System.Collections.IDictionary getFields(Message theMessage, System.Collections.IList theTerserPaths)
        {
            System.Collections.IDictionary fields = new System.Collections.Hashtable();
            Terser terser = new Terser(theMessage);

            for (int i = 0; i < theTerserPaths.Count; i++)
            {
                System.String path       = (System.String)theTerserPaths[i];
                System.String fieldValue = terser.get_Renamed(path);
                fields[path] = fieldValue;
            }
            return(fields);
        }
        /// <summary> Returns the first Application that has been bound to messages of this type.  </summary>
        private NuGenReceivingApplication findApplication(Message theMessage)
        {
            Terser         t       = new Terser(theMessage);
            AppRoutingData msgData = new NuGenAppRoutingDataImpl(t.get_Renamed("/MSH-9-1"), t.get_Renamed("/MSH-9-2"), t.get_Renamed("/MSH-11-1"), t.get_Renamed("/MSH-12"));

            NuGenReceivingApplication app = findDestination(msgData);

            //have to send back an application reject if no apps available to process
            if (app == null)
            {
                app = new NuGenAppWrapper(new DefaultApplication());
            }
            return(app);
        }
Example #14
0
        /// <summary> Creates an ACK message with the minimum required information from an inbound message.
        /// Optional fields can be filled in afterwards, before the message is returned.  Pleaase
        /// note that MSH-10, the outbound message control ID, is also set using the class
        /// <code>Genetibase.NuGenHL7.util.MessageIDGenerator</code>.  Also note that the ACK messages returned
        /// is the same version as the version stated in the inbound MSH if there is a generic ACK for that
        /// version, otherwise a version 2.4 ACK is returned. MSA-1 is set to AA by default.
        ///
        /// </summary>
        /// <param name="inboundHeader">the MSH segment if the inbound message
        /// </param>
        /// <throws>  IOException if there is a problem reading or writing the message ID file </throws>
        /// <throws>  DataTypeException if there is a problem setting ACK values </throws>
        public static Message makeACK(Segment inboundHeader)
        {
            if (!inboundHeader.getName().Equals("MSH"))
            {
                throw new NuGenHL7Exception("Need an MSH segment to create a response ACK (got " + inboundHeader.getName() + ")");
            }

            //make ACK of correct version
            System.String version = null;
            try
            {
                version = Terser.get_Renamed(inboundHeader, 12, 0, 1, 1);
            }
            catch (NuGenHL7Exception)
            {
                /* proceed with null */
            }
            if (version == null)
            {
                version = "2.4";
            }

            System.String ackClassName = SourceGenerator.getVersionPackageName(version) + "message.ACK";

            Message out_Renamed = null;

            try
            {
                System.Type ackClass = System.Type.GetType(ackClassName);
                out_Renamed = (Message)System.Activator.CreateInstance(ackClass);
            }
            catch (System.Exception e)
            {
                throw new NuGenHL7Exception("Can't instantiate ACK of class " + ackClassName + ": " + e.GetType().FullName);
            }
            Terser terser = new Terser(out_Renamed);

            //populate outbound MSH using data from inbound message ...
            Segment outHeader = (Segment)out_Renamed.get_Renamed("MSH");

            fillResponseHeader(inboundHeader, outHeader);

            terser.set_Renamed("/MSH-9", "ACK");
            terser.set_Renamed("/MSH-12", version);
            terser.set_Renamed("/MSA-1", "AA");
            terser.set_Renamed("/MSA-2", Genetibase.NuGenHL7.util.NuGenTerser.get_Renamed(inboundHeader, 10, 0, 1, 1));

            return(out_Renamed);
        }
		/// <seealso cref="Validator.validate">
		/// </seealso>
		public virtual NuGenHL7Exception[] validate(Message message, StaticDef profile)
		{
			System.Collections.ArrayList exList = new System.Collections.ArrayList(20);
			Terser t = new Terser(message);
			
			//check msg type, event type, msg struct ID
			System.String msgType = t.get_Renamed("/MSH-9-1");
			if (!msgType.Equals(profile.MsgType))
			{
				NuGenHL7Exception e = new NuGenProfileNotFollowedException("Message type " + msgType + " doesn't match profile type of " + profile.MsgType);
				exList.Add(e);
			}
			
			System.String evType = t.get_Renamed("/MSH-9-2");
			if (!evType.Equals(profile.EventType) && !profile.EventType.ToUpper().Equals("ALL".ToUpper()))
			{
				NuGenHL7Exception e = new NuGenProfileNotFollowedException("Event type " + evType + " doesn't match profile type of " + profile.EventType);
				exList.Add(e);
			}
			
			System.String msgStruct = t.get_Renamed("/MSH-9-3");
			if (msgStruct == null || !msgStruct.Equals(profile.MsgStructID))
			{
				NuGenHL7Exception e = new NuGenProfileNotFollowedException("Message structure " + msgStruct + " doesn't match profile type of " + profile.MsgStructID);
				exList.Add(e);
			}
			
			System.Exception[] childExceptions;
			childExceptions = testGroup(message, profile, profile.Identifier);
			for (int i = 0; i < childExceptions.Length; i++)
			{
				exList.Add(childExceptions[i]);
			}
			
			return toArray(exList);
		}
Example #16
0
        /// <seealso cref="Validator.validate">
        /// </seealso>
        public virtual NuGenHL7Exception[] validate(Message message, StaticDef profile)
        {
            System.Collections.ArrayList exList = new System.Collections.ArrayList(20);
            Terser t = new Terser(message);

            //check msg type, event type, msg struct ID
            System.String msgType = t.get_Renamed("/MSH-9-1");
            if (!msgType.Equals(profile.MsgType))
            {
                NuGenHL7Exception e = new NuGenProfileNotFollowedException("Message type " + msgType + " doesn't match profile type of " + profile.MsgType);
                exList.Add(e);
            }

            System.String evType = t.get_Renamed("/MSH-9-2");
            if (!evType.Equals(profile.EventType) && !profile.EventType.ToUpper().Equals("ALL".ToUpper()))
            {
                NuGenHL7Exception e = new NuGenProfileNotFollowedException("Event type " + evType + " doesn't match profile type of " + profile.EventType);
                exList.Add(e);
            }

            System.String msgStruct = t.get_Renamed("/MSH-9-3");
            if (msgStruct == null || !msgStruct.Equals(profile.MsgStructID))
            {
                NuGenHL7Exception e = new NuGenProfileNotFollowedException("Message structure " + msgStruct + " doesn't match profile type of " + profile.MsgStructID);
                exList.Add(e);
            }

            System.Exception[] childExceptions;
            childExceptions = testGroup(message, profile, profile.Identifier);
            for (int i = 0; i < childExceptions.Length; i++)
            {
                exList.Add(childExceptions[i]);
            }

            return(toArray(exList));
        }
Example #17
0
        private System.Collections.IDictionary getMetadata(Message theMessage)
        {
            System.Collections.IDictionary md = new System.Collections.Hashtable();
            Terser t = new Terser(theMessage);

            //snapshot so concurrent changes won't break our iteration

            Object[] fields = new Object[MetadataFields.Count];
            MetadataFields.CopyTo(fields, 0);

            for (int i = 0; i < fields.Length; i++)
            {
                System.String field = fields[i].ToString();
                System.String val   = t.get_Renamed(field);
                md[field] = val;
            }

            return(md);
        }
        /// <summary> Processes an incoming message string and returns the response message string.
        /// Message processing consists of parsing the message, finding an appropriate
        /// Application and processing the message with it, and encoding the response.
        /// Applications are chosen from among those registered using
        /// <code>bindApplication</code>.
        ///
        /// </summary>
        /// <returns> {text, charset}
        /// </returns>
        private System.String[] processMessage(System.String incomingMessageString, System.Collections.IDictionary theMetadata)
        {
            ;

            Message incomingMessageObject = null;

            System.String outgoingMessageString  = null;
            System.String outgoingMessageCharset = null;
            try
            {
                incomingMessageObject = myParser.parse(incomingMessageString);
            }
            catch (NuGenHL7Exception e)
            {
                outgoingMessageString = Responder.logAndMakeErrorMessage(e, myParser.getCriticalResponseData(incomingMessageString), myParser, myParser.getEncoding(incomingMessageString));
            }

            if (outgoingMessageString == null)
            {
                try
                {
                    //message validation (in terms of optionality, cardinality) would go here ***

                    NuGenReceivingApplication app = findApplication(incomingMessageObject);
                    theMetadata[RAW_MESSAGE_KEY] = incomingMessageString;
                    Message response = app.processMessage(incomingMessageObject, theMetadata);

                    //Here we explicitly use the same encoding as that of the inbound message - this is important with GenericParser, which might use a different encoding by default
                    outgoingMessageString = myParser.encode(response, myParser.getEncoding(incomingMessageString));

                    Terser t = new Terser(response);
                    outgoingMessageCharset = t.get_Renamed("MSH-18");
                }
                catch (System.Exception e)
                {
                    outgoingMessageString = Responder.logAndMakeErrorMessage(e, (Segment)incomingMessageObject.get_Renamed("MSH"), myParser, myParser.getEncoding(incomingMessageString));
                }
            }

            return(new System.String[] { outgoingMessageString, outgoingMessageCharset });
        }
Example #19
0
        /// <summary> Populates certain required fields in a response message header, using
        /// information from the corresponding inbound message.  The current time is
        /// used for the message time field, and <code>MessageIDGenerator</code> is
        /// used to create a unique message ID.  Version and message type fields are
        /// not populated.
        /// </summary>
        public static void  fillResponseHeader(Segment inbound, Segment outbound)
        {
            if (!inbound.getName().Equals("MSH") || !outbound.getName().Equals("MSH"))
            {
                throw new NuGenHL7Exception("Need MSH segments.  Got " + inbound.getName() + " and " + outbound.getName());
            }

            //get MSH data from incoming message ...
            System.String encChars = Terser.get_Renamed(inbound, 2, 0, 1, 1);
            System.String fieldSep = Terser.get_Renamed(inbound, 1, 0, 1, 1);
            System.String procID   = Terser.get_Renamed(inbound, 11, 0, 1, 1);

            //populate outbound MSH using data from inbound message ...
            Terser.set_Renamed(outbound, 2, 0, 1, 1, encChars);
            Terser.set_Renamed(outbound, 1, 0, 1, 1, fieldSep);
            System.Globalization.GregorianCalendar now = new System.Globalization.GregorianCalendar();
            SupportClass.CalendarManager.manager.SetDateTime(now, System.DateTime.Now);
            Terser.set_Renamed(outbound, 7, 0, 1, 1, CommonTS.toHl7TSFormat(now));
            Terser.set_Renamed(outbound, 10, 0, 1, 1, MessageIDGenerator.Instance.NewID);
            Terser.set_Renamed(outbound, 11, 0, 1, 1, procID);
        }
		/// <summary> Returns the first Application that has been bound to messages of this type.  </summary>
		private NuGenReceivingApplication findApplication(Message theMessage)
		{
			Terser t = new Terser(theMessage);
			AppRoutingData msgData = new NuGenAppRoutingDataImpl(t.get_Renamed("/MSH-9-1"), t.get_Renamed("/MSH-9-2"), t.get_Renamed("/MSH-11-1"), t.get_Renamed("/MSH-12"));
			
			NuGenReceivingApplication app = findDestination(msgData);
			
			//have to send back an application reject if no apps available to process
			if (app == null)
				app = new NuGenAppWrapper(new DefaultApplication());
			return app;
		}
Example #21
0
		/// <summary> Sends a message to a responder system, receives the reply, and 
		/// returns the reply as a Message object.  This method is thread-safe - multiple  
		/// threads can share an Initiator and call this method.  Responses are returned to 
		/// the calling thread on the basis of message ID.  
		/// </summary>
		public virtual Message sendAndReceive(Message out_Renamed)
		{
			
			if (out_Renamed == null)
				throw new NuGenHL7Exception("Can't encode null message", NuGenHL7Exception.REQUIRED_FIELD_MISSING);
			
			//register message with response Receiver(s) (by message ID)
			Terser t = new Terser(out_Renamed);
			System.String messID = t.get_Renamed("/MSH-10");
			NuGenMessageReceipt mr = this.conn.reserveResponse(messID);
			
			//log and send message 
			System.String outbound = conn.Parser.encode(out_Renamed);
			
			try
			{
				this.conn.SendWriter.writeMessage(outbound);
			}
			catch (System.IO.IOException e)
			{
				conn.close();
				throw e;
			}
			
			//wait for response
			bool done = false;
			Message response = null;
			long startTime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
			while (!done)
			{
				lock (mr)
				{
					try
					{
						System.Threading.Monitor.Wait(mr, TimeSpan.FromMilliseconds(500)); //if it comes, notifyAll() will be called
					}
					catch (System.Threading.ThreadInterruptedException)
					{
					}
					
					if (mr.Message != null)
					{
						//get message from receipt 
						System.String inbound = mr.Message;
						
						//parse message
						response = conn.Parser.parse(inbound);
						done = true;
					}
					
					//if ((System.DateTime.Now.Ticks - 621355968000000000) / 10000 > startTime + timeoutMillis)
						//throw new HL7Exception("Timeout waiting for response to message with control ID '" + messID);
				}
			}
			
			return response;
		}
		/// <summary> Processes an incoming message string and returns the response message string.
		/// Message processing consists of parsing the message, finding an appropriate
		/// Application and processing the message with it, and encoding the response.
		/// Applications are chosen from among those registered using
		/// <code>bindApplication</code>.  
		/// 
		/// </summary>
		/// <returns> {text, charset}
		/// </returns>
		private System.String[] processMessage(System.String incomingMessageString, System.Collections.IDictionary theMetadata)
		{;
			
			Message incomingMessageObject = null;
			System.String outgoingMessageString = null;
			System.String outgoingMessageCharset = null;
			try
			{
				incomingMessageObject = myParser.parse(incomingMessageString);
			}
			catch (NuGenHL7Exception e)
			{
				outgoingMessageString = Responder.logAndMakeErrorMessage(e, myParser.getCriticalResponseData(incomingMessageString), myParser, myParser.getEncoding(incomingMessageString));
			}
			
			if (outgoingMessageString == null)
			{
				try
				{				
					//message validation (in terms of optionality, cardinality) would go here ***
					
					NuGenReceivingApplication app = findApplication(incomingMessageObject);
					theMetadata[RAW_MESSAGE_KEY] = incomingMessageString;
					Message response = app.processMessage(incomingMessageObject, theMetadata);
					
					//Here we explicitly use the same encoding as that of the inbound message - this is important with GenericParser, which might use a different encoding by default
					outgoingMessageString = myParser.encode(response, myParser.getEncoding(incomingMessageString));
					
					Terser t = new Terser(response);
					outgoingMessageCharset = t.get_Renamed("MSH-18");
				}
				catch (System.Exception e)
				{
					outgoingMessageString = Responder.logAndMakeErrorMessage(e, (Segment) incomingMessageObject.get_Renamed("MSH"), myParser, myParser.getEncoding(incomingMessageString));
				}
			}
			
			return new System.String[]{outgoingMessageString, outgoingMessageCharset};
		}
		/// <summary> Returns the Applications that has been registered to handle 
		/// messages of the type and trigger event of the given message, or null if 
		/// there are none. 
		/// </summary>
		private NuGenApplication getMatchingApplication(Message message)
		{
			Terser t = new Terser(message);
			System.String messageType = t.get_Renamed("/MSH-9-1");
			System.String triggerEvent = t.get_Renamed("/MSH-9-2");
			return this.getMatchingApplication(messageType, triggerEvent);
		}
		private System.String[] getDeclaredProfileIDs(Message theMessage)
		{
			Terser t = new Terser(theMessage);
			bool noMore = false;
			int c = 0;
			System.Collections.ArrayList declaredProfiles = new System.Collections.ArrayList(8);
			while (!noMore)
			{
				System.String path = "MSH-21(" + c++ + ")";
				System.String idRep = t.get_Renamed(path);
				//FIXME fails if empty rep precedes full rep ... should add getAll() to Terser and use that
				if (idRep == null || idRep.Equals(""))
				{
					noMore = true;
				}
				else
				{
					declaredProfiles.Add(idRep);
				}
			}

            String[] retVal = new String[declaredProfiles.Count];
            declaredProfiles.CopyTo(retVal);

            return retVal;
		}