/// <summary> <p>Returns a minimal amount of data from a message string, including only the /// data needed to send a response to the remote system. This includes the /// following fields: /// <ul><li>field separator</li> /// <li>encoding characters</li> /// <li>processing ID</li> /// <li>message control ID</li></ul> /// This method is intended for use when there is an error parsing a message, /// (so the Message object is unavailable) but an error message must be sent /// back to the remote system including some of the information in the inbound /// message. This method parses only that required information, hopefully /// avoiding the condition that caused the original error. The other /// fields in the returned MSH segment are empty.</p> /// </summary> public override ISegment GetCriticalResponseData(System.String message) { //try to get MSH segment int locStartMSH = message.IndexOf("MSH"); if (locStartMSH < 0) { throw new HL7Exception("Couldn't find MSH segment in message: " + message, HL7Exception.SEGMENT_SEQUENCE_ERROR); } int locEndMSH = message.IndexOf('\r', locStartMSH + 1); if (locEndMSH < 0) { locEndMSH = message.Length; } System.String mshString = message.Substring(locStartMSH, (locEndMSH) - (locStartMSH)); //find out what the field separator is char fieldSep = mshString[3]; //get field array System.String[] fields = Split(mshString, System.Convert.ToString(fieldSep)); ISegment msh = null; try { //parse required fields System.String encChars = fields[1]; char compSep = encChars[0]; System.String messControlID = fields[9]; System.String[] procIDComps = Split(fields[10], System.Convert.ToString(compSep)); //fill MSH segment System.String version = "2.4"; //default try { version = this.GetVersion(message); } catch (System.Exception) { /* use the default */ } msh = ParserBase.MakeControlMSH(version, Factory); Terser.Set(msh, 1, 0, 1, 1, System.Convert.ToString(fieldSep)); Terser.Set(msh, 2, 0, 1, 1, encChars); Terser.Set(msh, 10, 0, 1, 1, messControlID); Terser.Set(msh, 11, 0, 1, 1, procIDComps[0]); } catch (System.Exception e) { SupportClass.WriteStackTrace(e, Console.Error); throw new HL7Exception("Can't parse critical fields from MSH segment (" + e.GetType().FullName + ": " + e.Message + "): " + mshString, HL7Exception.REQUIRED_FIELD_MISSING); } return(msh); }
/// <summary> Finds a message or segment class by name and version.</summary> /// <param name="name">the segment or message structure name. /// </param> /// <param name="version">the HL7 version. /// </param> /// <param name="type">'message', 'group', 'segment', or 'datatype'. /// </param> private static Type FindClass(string name, string version, ClassType type) { if (ParserBase.ValidVersion(version) == false) { throw new HL7Exception("The HL7 version " + version + " is not recognized", ErrorCode.UNSUPPORTED_VERSION_ID); } // get list of packages to search for the corresponding message class var packages = PackageList(version); // get sub-package for component type var typeString = type.ToString(); var subpackage = typeString.Substring(0, 1).ToUpper() + typeString.Substring(1); // try to load class from each package Type compClass = null; var c = 0; while (compClass == null && c < packages.Count) { try { var p = packages[c]; if (!p.EndsWith(".")) { p = p + "."; } var classNameToTry = p + subpackage + "." + name; classNameToTry = AddAssemblyName(p, classNameToTry); if (Log.DebugEnabled) { Log.Debug("Trying to load: " + classNameToTry); } compClass = Type.GetType(classNameToTry); if (Log.DebugEnabled) { Log.Debug("Loaded: " + classNameToTry + " class: " + compClass); } } catch (Exception) { /* just try next one */ } c++; } return(compClass); }
/// <summary> /// <p>Attempts to return the message class corresponding to the given name, by searching through /// default and user-defined (as per PackageList()) packages. Returns GenericMessage if the class /// is not found.</p> /// <p>It is important to note that there can only be one implementation of a particular message /// structure (i.e. one class with the message structure name, regardless of its package) among /// the packages defined as per the <code>PackageList()</code> method. If there are duplicates /// (e.g. two ADT_A01 classes) the first one in the search order will always be used. However, /// this restriction only applies to message classes, not (normally) segment classes, etc. This /// is because classes representing parts of a message are referenced explicitly in the code for /// the message class, rather than being looked up (using findMessageClass() ) based on the /// String value of MSH-9. The exception is that Segments may have to be looked up by name when /// they appear in unexpected locations (e.g. by local extension) -- see findSegmentClass().</p> /// <p>Note: the current implementation will be slow if there are multiple user- defined packages, /// because the JVM will try to load a number of non-existent classes every parse. This should /// be changed so that specific classes, rather than packages, are registered by name.</p> /// </summary> /// /// <param name="theName"> name of the desired structure in the form XXX_YYY. </param> /// <param name="theVersion"> HL7 version (e.g. "2.3") </param> /// <param name="isExplicit"> true if the structure was specified explicitly in MSH-9-3, false /// if it was inferred from MSH-9-1 and MSH-9-2. If false, a lookup /// may be performed to find an alternate structure corresponding to /// that message type and event. </param> /// /// <returns> corresponding message subclass if found; GenericMessage otherwise. </returns> public virtual System.Type GetMessageClass(System.String theName, System.String theVersion, bool isExplicit) { System.Type mc = null; if (!isExplicit) { theName = ParserBase.GetMessageStructureForEvent(theName, theVersion); } mc = findClass(theName, theVersion, ClassType.Message); if (mc == null) { mc = GenericMessage.getGenericMessageClass(theVersion); } return(mc); }
public static new void Main(System.String[] args) { if (args.Length != 1) { System.Console.Out.WriteLine("Usage: DefaultXMLParser pipe_encoded_file"); System.Environment.Exit(1); } //read and parse message from file try { System.IO.FileInfo messageFile = new System.IO.FileInfo(args[0]); long fileLength = SupportClass.FileLength(messageFile); System.IO.StreamReader r = new System.IO.StreamReader( messageFile.FullName, System.Text.Encoding.Default); char[] cbuf = new char[(int)fileLength]; System.Console.Out.WriteLine( "Reading message file ... " + r.Read(cbuf, 0, cbuf.Length) + " of " + fileLength + " chars"); r.Close(); System.String messString = System.Convert.ToString(cbuf); ParserBase inParser = null; ParserBase outParser = null; PipeParser pp = new PipeParser(); NHapi.Base.Parser.XMLParser xp = new DefaultXMLParser(); System.Console.Out.WriteLine("Encoding: " + pp.GetEncoding(messString)); if (pp.GetEncoding(messString) != null) { inParser = pp; outParser = xp; } else if (xp.GetEncoding(messString) != null) { inParser = xp; outParser = pp; } IMessage mess = inParser.Parse(messString); System.Console.Out.WriteLine("Got message of type " + mess.GetType().FullName); System.String otherEncoding = outParser.Encode(mess); System.Console.Out.WriteLine(otherEncoding); } catch (System.Exception e) { SupportClass.WriteStackTrace(e, Console.Error); } }
/// <summary> /// <p>Returns a minimal amount of data from a message string, including only the data needed to /// send a response to the remote system. This includes the following fields: /// <ul><li>field separator</li> /// <li>encoding characters</li> /// <li>processing ID</li> /// <li>message control ID</li></ul> /// This method is intended for use when there is an error parsing a message, (so the Message /// object is unavailable) but an error message must be sent back to the remote system including /// some of the information in the inbound message. This method parses only that required /// information, hopefully avoiding the condition that caused the original error.</p> /// </summary> /// /// <param name="message"> a String that contains an HL7 message. </param> /// /// <returns> The critical response data. </returns> public override ISegment GetCriticalResponseData(System.String message) { System.String version = this.GetVersion(message); ISegment criticalData = ParserBase.MakeControlMSH(version, this.Factory); Terser.Set(criticalData, 1, 0, 1, 1, this.ParseLeaf(message, "MSH.1", 0)); Terser.Set(criticalData, 2, 0, 1, 1, this.ParseLeaf(message, "MSH.2", 0)); Terser.Set(criticalData, 10, 0, 1, 1, this.ParseLeaf(message, "MSH.10", 0)); System.String procID = this.ParseLeaf(message, "MSH.11", 0); if (procID == null || procID.Length == 0) { procID = this.ParseLeaf(message, "PT.1", message.IndexOf("MSH.11")); //this field is a composite in later versions } Terser.Set(criticalData, 11, 0, 1, 1, procID); return(criticalData); }