/// <summary> Returns the Applications that has been registered to handle /// messages of the given type and trigger event, or null if /// there are none. If there is not an exact match, wildcards /// ("*") are tried as well. /// </summary> private NuGenApplication getMatchingApplication(System.String messageType, System.String triggerEvent) { lock (this) { NuGenApplication matchingApp = null; System.Object o = this.apps[getKey(messageType, triggerEvent)]; if (o == null) { o = this.apps[getKey(messageType, "*")]; } if (o == null) { o = this.apps[getKey("*", triggerEvent)]; } if (o == null) { o = this.apps[getKey("*", "*")]; } if (o != null) { matchingApp = (NuGenApplication)o; } return(matchingApp); } }
/// <summary> Forwards the given message to any Applications that have been registered to /// accept messages of that type and trigger event. /// </summary> /// <throws> ApplicationException if no such Applications are registered, or if </throws> /// <summary> the underlying Application throws this exception during processing. /// </summary> public virtual Message processMessage(Message in_Renamed) { Message out_Renamed; try { NuGenApplication matchingApp = this.getMatchingApplication(in_Renamed); out_Renamed = matchingApp.processMessage(in_Renamed); } catch (NuGenHL7Exception e) { throw new NuGenApplicationException("Error internally routing message: " + e.ToString(), e); } return(out_Renamed); }
/// <summary> Registers the given application to handle messages corresponding to the given type /// and trigger event. Only one application can be registered for a given message type /// and trigger event combination. A repeated registration for a particular combination /// of type and trigger event over-writes the previous one. Use "*" as a wildcard (e.g. /// registerApplication("ADT", "*", myApp) would register your app for all ADT messages). /// </summary> public virtual void registerApplication(System.String messageType, System.String triggerEvent, NuGenApplication handler) { lock (this) { this.apps[getKey(messageType, triggerEvent)] = handler; //status message System.Text.StringBuilder buf = new System.Text.StringBuilder(); buf.Append(handler.GetType().FullName); buf.Append(" registered to handle "); buf.Append(messageType); buf.Append("^"); buf.Append(triggerEvent); buf.Append(" messages"); } }
/// <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>registerApplication</code>. The Parser is obtained from the Connection /// associated with this Responder. /// </summary> protected internal virtual System.String processMessage(System.String incomingMessageString) { Message incomingMessageObject = null; System.String outgoingMessageString = null; try { incomingMessageObject = parser.parse(incomingMessageString); } catch (NuGenHL7Exception e) { outgoingMessageString = logAndMakeErrorMessage(e, parser.getCriticalResponseData(incomingMessageString), parser, parser.getEncoding(incomingMessageString)); } if (outgoingMessageString == null) { try { //optionally check integrity of parse try { if (checkWriter != null) { checkParse(incomingMessageString, incomingMessageObject, parser); } } catch (System.IO.IOException) { } //message validation (in terms of optionality, cardinality) would go here *** NuGenApplication app = findApplication(incomingMessageObject); Message response = app.processMessage(incomingMessageObject); //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 = parser.encode(response, parser.getEncoding(incomingMessageString)); } catch (System.Exception e) { outgoingMessageString = logAndMakeErrorMessage(e, (Segment)incomingMessageObject.get_Renamed("MSH"), parser, parser.getEncoding(incomingMessageString)); } } return(outgoingMessageString); }
/// <summary> Returns true if at least one application has been registered to accept this /// type of message. Applications are registered using <code>registerApplication(...)</code>. /// </summary> public virtual bool canProcess(Message in_Renamed) { bool can = false; try { NuGenApplication matches = this.getMatchingApplication(in_Renamed); if (matches != null) { can = true; } } catch (NuGenHL7Exception) { can = false; } return(can); }
/// <summary> Returns the first Application that has been registered, which can process the given /// Message (according to its canProcess() method). /// </summary> private NuGenApplication findApplication(Message message) { int c = 0; NuGenApplication app = null; while (app == null && c < this.apps.Count) { NuGenApplication a = (NuGenApplication)this.apps[c++]; if (a.canProcess(message)) { app = a; } } //have to send back an application reject of no apps available to process if (app == null) { app = new NuGenDefaultApplication(); } return(app); }
/// <summary> <p>A convenience method for registering applications (using <code>registerApplication() /// </code>) with this service. Information about which Applications should handle which /// messages is read from the given text file. Each line in the file should have the /// following format (entries tab delimited):</p> /// <p>message_type 	 trigger_event 	 application_class</p> /// <p>message_type 	 trigger_event 	 application_class</p> /// <p>Note that message type and event can be the wildcard "*", which means any.</p> /// <p>For example, if you write an Application called org.yourorganiztion.ADTProcessor /// that processes several types of ADT messages, and another called /// org.yourorganization.ResultProcessor that processes result messages, you might have a /// file that looks like this: </p> /// <p>ADT 	 * 	 org.yourorganization.ADTProcessor<br> /// ORU 	 R01 	 org.yourorganization.ResultProcessor</p> /// <p>Each class listed in this file must implement Application and must have a zero-argument /// constructor.</p> /// </summary> public virtual void loadApplicationsFromFile(System.IO.FileInfo f) { System.IO.StreamReader in_Renamed = new System.IO.StreamReader(new System.IO.StreamReader(f.FullName, System.Text.Encoding.Default).BaseStream, new System.IO.StreamReader(f.FullName, System.Text.Encoding.Default).CurrentEncoding); System.String line = null; while ((line = in_Renamed.ReadLine()) != null) { //parse application registration information SupportClass.Tokenizer tok = new SupportClass.Tokenizer(line, "\t", false); System.String type = null, event_Renamed = null, className = null; if (tok.HasMoreTokens()) { //skip blank lines try { type = tok.NextToken(); event_Renamed = tok.NextToken(); className = tok.NextToken(); } catch (System.ArgumentOutOfRangeException) { throw new NuGenHL7Exception("Can't register applications from file " + f.Name + ". The line '" + line + "' is not of the form: message_type [tab] trigger_event [tab] application_class.", NuGenHL7Exception.APPLICATION_INTERNAL_ERROR); } System.Type appClass = System.Type.GetType(className); //may throw ClassNotFoundException System.Object appObject = System.Activator.CreateInstance(appClass); NuGenApplication app = null; try { app = (NuGenApplication)appObject; } catch (System.InvalidCastException) { throw new NuGenHL7Exception("The specified class, " + appClass.FullName + ", doesn't implement Application.", NuGenHL7Exception.APPLICATION_INTERNAL_ERROR); } this.registerApplication(type, event_Renamed, app); } } }
/// <summary> Registers a message parser/encoder with this responder. If multiple parsers /// are registered, each message is inspected by each parser in the order in which /// they are registered, until one parser recognizes the format and parses the /// message. /// </summary> /*public void registerParser(Parser p) { this.parsers.add(p); }*/ /// <summary> Registers an Application with this Responder. The "Application", in this /// context, is the software that uses the information in the message. If multiple /// applications are registered, incoming Message objects will be passed to /// each one in turn (calling <code>canProcess()</code>) until one of them accepts /// responsibility for the message. If none of the registered applications can /// process the message, a DefaultApplication is used, which simply returns an /// Application Reject message. /// </summary> public virtual void registerApplication(NuGenApplication a) { this.apps.Add(a); }
/// <summary> Registers the given application to handle messages corresponding to the given type /// and trigger event. Only one application can be registered for a given message type /// and trigger event combination. A repeated registration for a particular combination /// of type and trigger event over-writes the previous one. Note that the wildcard "*" /// for messageType or triggerEvent means any type or event, respectively. /// </summary> public virtual void registerApplication(System.String messageType, System.String triggerEvent, NuGenApplication handler) { lock (this) { this.router.registerApplication(messageType, triggerEvent, handler); } }
/// <summary> Registers a message parser/encoder with this responder. If multiple parsers /// are registered, each message is inspected by each parser in the order in which /// they are registered, until one parser recognizes the format and parses the /// message. /// </summary> /*public void registerParser(Parser p) { * this.parsers.add(p); * }*/ /// <summary> Registers an Application with this Responder. The "Application", in this /// context, is the software that uses the information in the message. If multiple /// applications are registered, incoming Message objects will be passed to /// each one in turn (calling <code>canProcess()</code>) until one of them accepts /// responsibility for the message. If none of the registered applications can /// process the message, a DefaultApplication is used, which simply returns an /// Application Reject message. /// </summary> public virtual void registerApplication(NuGenApplication a) { this.apps.Add(a); }