All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dellroad.hl7.HL7Message Maven / Gradle / Ivy

The newest version!

/*
 * Copyright (C) 2008 Archie L. Cobbs. All rights reserved.
 */

package org.dellroad.hl7;

import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Represents an HL7 message.
 */
@SuppressWarnings("serial")
public class HL7Message implements Serializable {

    /**
     * The character that separates segments in an HL7 message.
     */
    public static final char SEGMENT_TERMINATOR = '\r';

    private static final Pattern FIELD_NAME_PATTERN = Pattern.compile("([\\p{Alnum}]{3})\\.[0-9]+");

    private static final Pattern VALUE_NAME_PATTERN = Pattern.compile("(" + FIELD_NAME_PATTERN + ")(\\.([0-9]+)(\\.([0-9]+))?)?");

    /**
     * The segments in this message. This list always contains at least
     * one element, namely the {@link MSHSegment}.
     */
    protected final HL7SegmentList segments;

    /**
     * Construct a new HL7 message containing only the given MSH segment.
     *
     * @param msh MSH segment
     */
    public HL7Message(MSHSegment msh) {
        this.segments = new HL7SegmentList(msh);
    }

    /**
     * Construct an empty HL7 message.
     *
     * 

* A MSH segment will be automatically added. * * @param seps separator and escape characters to use for this message */ public HL7Message(HL7Seps seps) { this.segments = new HL7SegmentList(new MSHSegment(seps)); } /** * Convenience constructor. Equivalent to: *

* HL7Message(HL7Seps.DEFAULT) *
*/ public HL7Message() { this(HL7Seps.DEFAULT); } /** * Parsing constructor. Constructs an HL7 message by parsing the given string. * Segments must be separated with a carriage return character. * * @param msg string-encoded message * @throws HL7ContentException if the string is invalid */ public HL7Message(String msg) throws HL7ContentException { // Eliminate trailing CR's int len = msg.length(); while (len > 0 && msg.charAt(len - 1) == SEGMENT_TERMINATOR) msg = msg.substring(0, --len); // Split message into segments int[] segs = HL7Util.find(msg, SEGMENT_TERMINATOR); // Get MSH segment with message-specific separator characters MSHSegment msh = new MSHSegment(msg.substring(0, segs[0])); this.segments = new HL7SegmentList(msh); HL7Seps seps = msh.getHL7Seps(); // Add subsequent segments for (int i = 0; i < segs.length - 1; i++) this.segments.add(new HL7Segment(msg.substring(segs[i] + 1, segs[i + 1]), seps)); } /** * Get the MSH segment of this message. * * @return this message's MSH segment (not a copy; changes are reflected back) */ public MSHSegment getMSHSegment() { return (MSHSegment)this.segments.get(0); } /** * Get all of the segments in this message. * *

* The returned list does not allow removing the first element (the MSH segment) or changing it to anything other than an * {@link MSHSegment}. * * @return list of all message segments including MSH */ public HL7SegmentList getSegments() { return this.segments; } /** * Get the first occurrence of a segname segment in this message. * * @param segname segment name, e.g., "PV1" * @param segnum starting segment index to start search; * index zero refers to the MSH segment * @return first matching segment found, or null if not found * @throws IllegalArgumentException if segnum is negative */ public HL7Segment findSegment(String segname, int segnum) { if (segnum < 0) throw new IllegalArgumentException("segnum=" + segnum); for (int i = segnum; i < this.segments.size(); i++) { HL7Segment seg = this.segments.get(i); if (seg.getName().equals(segname)) return seg; } return null; } /** * Convenience method. Equivalent to: *

* findSegment(name, 0) *
* * @param segname segment name, e.g., "PV1" * @return first matching segment found, or null if not found */ public HL7Segment findSegment(String segname) { return this.findSegment(segname, 0); } /** * Find a field by HL7 name. The name is of the form XYZ.N where * "XYZ" is the segment name and "N" is the field number. * * @param name field name, e.g., "PV1.3" * @param segnum starting segment index (zero to start from MSH segment) * @return named HL7 field, or null if the named field doesn't exist in this message * @throws IllegalArgumentException if name is not properly formatted * @throws IllegalArgumentException if segnum is negative */ public HL7Field getField(String name, int segnum) { // Check parameters Matcher matcher = FIELD_NAME_PATTERN.matcher(name); if (!matcher.matches()) throw new IllegalArgumentException("invalid name `" + name + "'"); int fieldIndex; try { fieldIndex = Integer.parseInt(name.substring(4), 10); } catch (NumberFormatException e) { throw new IllegalArgumentException("invalid name `" + name + "'"); } // Find segment, then field HL7Segment seg = this.findSegment(name.substring(0, 3), segnum); return seg != null ? seg.getField(fieldIndex) : null; } /** * Convenience method. Equivalent to: *
* getField(name, 0) *
* * @param name field name, e.g., "PV1.3" * @return named HL7 field, or null if the named field doesn't exist in this message */ public HL7Field getField(String name) { return this.getField(name, 0); } /** * Find a string value by HL7 name. The name is of the form {@code XYZ.N[.M[.L]]} * where {@code XYZ} is the segment name, {@code N} is the field number, {@code M} is the * optional component number, and {@code L} is the optional subcomponent number. * *

* If either of {@code M} or {@code L} are not given, they are assumed to be {@code 1} * so an unambiguous string value can always be returned. * * @param name HL7 value name, e.g., "PV1.3", "MSH.9.1", "ZZZ.3.2.1" * @param segnum starting segment index * @param repeat repeat index (starting from zero) * @return named HL7 value, or null if the named value doesn't exist in this message * @throws IllegalArgumentException if name is not properly formatted * @throws IllegalArgumentException if "M" or "L" is negative * @throws IllegalArgumentException if segnum or repeat is negative */ public String get(String name, int segnum, int repeat) { // Find field first Matcher matcher = VALUE_NAME_PATTERN.matcher(name); if (!matcher.matches()) throw new IllegalArgumentException("invalid name `" + name + "'"); HL7Field field = this.getField(matcher.group(1), segnum); if (field == null) return null; // Get component and subcomponent indicies int component = 0; String value = matcher.group(4); if (value != null) { try { component = Integer.parseInt(value, 10) - 1; } catch (NumberFormatException e) { throw new IllegalArgumentException("invalid component index `" + value + "'"); } } int subcomponent = 0; value = matcher.group(6); if (value != null) { try { subcomponent = Integer.parseInt(value, 10) - 1; } catch (NumberFormatException e) { throw new IllegalArgumentException("invalid subcomponent index `" + value + "'"); } } // Return value (if any) return field.get(repeat, component, subcomponent); } /** * Convenience method. Equivalent to: *

* get(name, 0, 0) *
* * @param name HL7 value name, e.g., "PV1.3", "MSH.9.1", "ZZZ.3.2.1" * @return named HL7 field, or null if the named field doesn't exist in this message */ public String get(String name) { return this.get(name, 0, 0); } @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj == null || obj.getClass() != getClass()) return false; final HL7Message that = (HL7Message)obj; return this.segments.equals(that.segments); } @Override public int hashCode() { return this.segments.hashCode(); } /** * Convert this message into a string by concatenating the segments in string form, each terminated with a carriage return. */ @Override public String toString() { return this.toString(getMSHSegment().getHL7Seps()); } /** * Format this message using the supplied separators instead of the ones defined by the MSH segment. If seps * does not define an escape character, then characters that need to be escaped are silently elided. * * @param seps HL7 separator characters * @return string encoding of this message */ public String toString(HL7Seps seps) { StringBuilder buf = new StringBuilder(); for (HL7Segment segment : this.segments) { segment.append(buf, seps); buf.append(SEGMENT_TERMINATOR); } return buf.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy