예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        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);
            }
        }
예제 #5
0
        /// <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);
        }