ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageBase.java Source code

Java tutorial

Introduction

Here is the source code for ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageBase.java

Source

/**
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
 * specific language governing rights and limitations under the License.
 *
 * The Original Code is ""  Description:
 * ""
 *
 * The Initial Developer of the Original Code is University Health Network. Copyright (C)
 * 2001.  All Rights Reserved.
 *
 * Contributor(s): ______________________________________.
 *
 * Alternatively, the contents of this file may be used under the terms of the
 * GNU General Public License (the  "GPL"), in which case the provisions of the GPL are
 * applicable instead of those above.  If you wish to allow use of your version of this
 * file only under the terms of the GPL and not to allow others to use your version
 * of this file under the MPL, indicate your decision by deleting  the provisions above
 * and replace  them with the notice and other provisions required by the GPL License.
 * If you do not delete the provisions above, a recipient may use your version of
 * this file under either the MPL or the GPL.
 */
package ca.uhn.hl7v2.testpanel.model.msg;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.util.List;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.conf.ProfileException;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.Segment;
import ca.uhn.hl7v2.parser.EncodingCharacters;
import ca.uhn.hl7v2.parser.EncodingNotSupportedException;
import ca.uhn.hl7v2.parser.GenericParser;
import ca.uhn.hl7v2.preparser.PreParser;
import ca.uhn.hl7v2.testpanel.model.conf.ConformanceMessage;
import ca.uhn.hl7v2.testpanel.model.conf.ProfileGroup;
import ca.uhn.hl7v2.testpanel.model.conf.ProfileGroup.Entry;
import ca.uhn.hl7v2.testpanel.util.Range;
import ca.uhn.hl7v2.testpanel.util.SegmentAndComponentPath;
import ca.uhn.hl7v2.testpanel.xsd.Hl7V2EncodingTypeEnum;
import ca.uhn.hl7v2.testpanel.xsd.Hl7V2MessageDefinition;
import ca.uhn.hl7v2.util.Terser;
import ca.uhn.hl7v2.validation.impl.ValidationContextImpl;

public abstract class Hl7V2MessageBase extends AbstractMessage<Message> {

    private static final Logger ourLog = LoggerFactory.getLogger(Hl7V2MessageBase.class);
    private Hl7V2EncodingTypeEnum myEncoding = Hl7V2EncodingTypeEnum.ER_7;
    private int myIndexWithinCollection;
    private Message myParsedMessage;
    private GenericParser myParser;
    private ProfileGroup myRuntimeProfile;
    private String mySourceMessage;

    /**
     * Constructor
     */
    public Hl7V2MessageBase() {
        super();
        initParser();
    }

    public Hl7V2MessageBase(String theId) {
        super(theId);
        initParser();
    }

    public abstract Hl7V2MessageBase asEncoding(Hl7V2EncodingTypeEnum theEncoding);

    /**
     * Subclasses should make use of this method to export AbstractInterface
     * properties into the return value for {@link #exportConfigToXml()}
     */
    protected Hl7V2MessageDefinition exportConfig(Hl7V2MessageDefinition theConfig) {
        super.exportConfig(theConfig);
        theConfig.setText(mySourceMessage);

        return theConfig;
    }

    /**
     * {@inheritDoc }
     */
    @Override
    public Hl7V2MessageDefinition exportConfigToXml() {
        return exportConfig(new Hl7V2MessageDefinition());
    }

    /**
     * @return the encoding
     */
    public Hl7V2EncodingTypeEnum getEncoding() {
        return myEncoding;
    }

    public abstract String getHighlitedPath();

    public abstract Range getHighlitedRange();

    /**
     * @return the indexWithinCollection
     */
    public int getIndexWithinCollection() {
        return myIndexWithinCollection;
    }

    @Override
    public Class<Message> getMessageClass() {
        return Message.class;
    }

    public String getMessageDescription() {
        StringBuilder retVal = new StringBuilder();

        Terser t = new Terser(getParsedMessage());

        try {
            retVal.append(t.get("/.MSH-9-1"));
            retVal.append("^");
            retVal.append(t.get("/.MSH-9-2"));

            retVal.append(" ");

            retVal.append(t.get("/.MSH-10"));
        } catch (HL7Exception e) {
            ourLog.error("Failed to retrieve message props: ", e);
        }

        return retVal.toString();
    }

    @Override
    public Message getParsedMessage() {
        return myParsedMessage;
    }

    /**
     * @return the runtimeProfile
     */
    public ProfileGroup getRuntimeProfile() {
        return myRuntimeProfile;
    }

    @Override
    public String getSourceMessage() {
        return mySourceMessage;
    }

    private void initParser() {
        myParser = new GenericParser();
        myParser.setValidationContext(new ValidationContextImpl());
    }

    /**
     * @param theParsedMessage
     *            the parsedMessage to set
     */
    public void initWithParsedMessage(Message theParsedMessage) {
        myParsedMessage = theParsedMessage;
    }

    /**
     * Invoked when the source message is updated prior to notifying listeners
     */
    protected abstract void recalculateIndexes();

    /**
     * @param theEncoding
     *            the encoding to set
     */
    public void setEncoding(Hl7V2EncodingTypeEnum theEncoding) {
        Validate.notNull(theEncoding);
        if (ObjectUtils.equals(myEncoding, theEncoding)) {
            return;
        }

        myEncoding = theEncoding;
        updateParser();

        if (myParsedMessage == null) {
            return;
        }

        String prev = mySourceMessage;
        try {
            mySourceMessage = myParser.encode(getParsedMessage());
        } catch (HL7Exception e) {
            ourLog.error("Could not re-encode message: " + e.getMessage(), e);
        }

        firePropertyChange(SOURCE_MESSAGE_PROPERTY, prev, mySourceMessage);
    }

    public abstract void setHighlitedField(SegmentAndComponentPath thePath);

    public abstract void setHighlitedPathBasedOnRange(Range theAdd);

    public abstract void setHighlitedRangeBasedOnSegment(Segment... theSegment);

    /**
     * @param theIndexWithinCollection
     *            the indexWithinCollection to set
     */
    public void setIndexWithinCollection(int theIndexWithinCollection) {
        myIndexWithinCollection = theIndexWithinCollection;
    }

    public void setRuntimeProfile(ProfileGroup theRuntimeProfile) {
        if (myRuntimeProfile == theRuntimeProfile) {
            return;
        }
        myRuntimeProfile = theRuntimeProfile;

        if (mySourceMessage == null) {
            return;
        }

        // Force a refresh
        String sourceMessage = mySourceMessage;
        mySourceMessage = null;
        try {
            setSourceMessage(sourceMessage);
        } catch (PropertyVetoException e) {
            ourLog.error("Failed to parse message", e);
        }
    }

    @Override
    public void setSourceMessage(String theMessage) throws PropertyVetoException {
        theMessage = StringUtils.defaultString(theMessage);

        String original = mySourceMessage;
        if (mySourceMessage != null && mySourceMessage.equals(theMessage)) {
            return;
        }

        String sourceMessage = theMessage.trim();
        String text = sourceMessage.replaceAll("(\\r|\\n)+", "\r");

        updateParser();

        Message parsedMessage;
        try {

            ourLog.info("About to parse message");

            if (myRuntimeProfile != null) {
                Entry profile = determineRuntimeProfile(text);

                if (profile != null) {
                    parsedMessage = ConformanceMessage.newInstanceFromStaticDef(
                            profile.getProfileProxy().getProfile().getMessage(), profile.getTablesId());
                    parsedMessage.setParser(myParser);
                    parsedMessage.parse(text);
                } else {
                    parsedMessage = myParser.parse(text);
                }
            } else {
                parsedMessage = myParser.parse(text);
            }

            ourLog.info("Done parsing message");

        } catch (EncodingNotSupportedException e) {
            ourLog.error("Failed to parse message", e);
            throw new PropertyVetoException(e.getMessage(), null);
        } catch (HL7Exception e) {
            ourLog.error("Failed to parse message", e);
            throw new PropertyVetoException(e.getMessage(), null);
        } catch (IOException e) {
            ourLog.error("Failed to parse message", e);
            throw new PropertyVetoException(e.getMessage(), null);
        } catch (ProfileException e) {
            ourLog.error("Failed to parse message", e);
            throw new PropertyVetoException(e.getMessage(), null);
        }

        myParsedMessage = parsedMessage;
        mySourceMessage = sourceMessage;

        recalculateIndexes();

        firePropertyChange(PARSED_MESSAGE_PROPERTY, original, text);
    }

    private Entry determineRuntimeProfile(String text) throws HL7Exception {
        String[] fields = PreParser.getFields(text, "MSH-9-1", "MSH-9-2");
        Entry profile = null;
        try {
            profile = myRuntimeProfile.getProfileForMessage(fields[0], fields[1]);
            if (profile != null) {
                profile.getProfileProxy().getProfile();
            }
        } catch (IOException e) {
            ourLog.error("Failed to load profile", e);
            profile = null;
        } catch (ProfileException e) {
            ourLog.error("Failed to load profile", e);
            profile = null;
        }

        return profile;
    }

    private void updateParser() {

        // Parser caches structure information, so can't reuse them for
        // structures generated from conformance profiles
        if (myRuntimeProfile != null) {
            initParser();
        }

        switch (myEncoding) {
        case XML:
            myParser.setXMLParserAsPrimary();
            break;
        case ER_7:
        default:
            myParser.setPipeParserAsPrimary();
            break;
        }
    }

    public void updateSourceMessage(String theNewSource, int theChangeStart, int theChangeEnd)
            throws PropertyVetoException {

        theNewSource = theNewSource.replace('\n', '\r');
        theNewSource = theNewSource.replace("\n", "");

        if (mySourceMessage.equals(theNewSource.trim())) {
            return;
        }

        if (true) {
            setSourceMessage(theNewSource);
        }

        mySourceMessage = theNewSource;

        // System.out.println(theNewSource.replace("\r", "\n"));

        try {
            Entry profile = determineRuntimeProfile(theNewSource);
            if (profile != null) {
                myParsedMessage = ConformanceMessage.newInstanceFromStaticDef(
                        profile.getProfileProxy().getProfile().getMessage(), profile.getTablesId());
                myParsedMessage.setParser(myParser);
                myParsedMessage.parse(theNewSource);
            } else {
                myParsedMessage.parse(theNewSource);
            }
        } catch (HL7Exception e) {
            ourLog.error("Failed to parse message", e);
        } catch (IOException e) {
            ourLog.error("Failed to parse message", e);
        } catch (ProfileException e) {
            ourLog.error("Failed to parse message", e);
        }

        firePropertyChange(PARSED_MESSAGE_PROPERTY, null, null);
    }

    public void updateSourceMessageBasedOnParsedMessage() {
        String newMessage;
        try {
            newMessage = myParsedMessage.encode();

            String oldValue = mySourceMessage;
            mySourceMessage = newMessage;
            firePropertyChange(SOURCE_MESSAGE_PROPERTY, oldValue, myParsedMessage);

            recalculateIndexes();

        } catch (HL7Exception e) {
            ourLog.error("Failed to update parsed message", e);
        }
    }

    static Range findFieldRange(List<Integer> theField, int theRepNum, Range theSegmentRange,
            String theSourceMessage, Message theParsedMessage) {
        EncodingCharacters enc;
        try {
            enc = EncodingCharacters.getInstance(theParsedMessage);
        } catch (HL7Exception e) {
            ourLog.error("Failed to find field", e);
            return null;
        }

        int componentPathIndex = 0;
        Range currentRange = theSegmentRange;
        for (Integer next : theField) {

            char sep;
            int offset = next;
            switch (componentPathIndex) {
            case 0:
                sep = enc.getFieldSeparator();
                if (!theSegmentRange.applyTo(theSourceMessage).startsWith("MSH")) {
                    offset++;
                }
                break;
            case 1:
                sep = enc.getComponentSeparator();
                break;
            case 2:
            default:
                sep = enc.getSubcomponentSeparator();
                break;
            }

            while (offset > 0) {

                int nextSeparatorIndex = theSourceMessage.indexOf(sep, currentRange.getStart());
                if (nextSeparatorIndex == -1 || nextSeparatorIndex > currentRange.getEnd()) {
                    if (offset > 1) {
                        nextSeparatorIndex = currentRange.getEnd() - 1;
                    } else {
                        nextSeparatorIndex = currentRange.getEnd();
                    }
                }

                if (offset > 1) {
                    currentRange = new Range(nextSeparatorIndex + 1, currentRange.getEnd());
                } else {

                    if (componentPathIndex == 0) {
                        char repSep = enc.getRepetitionSeparator();
                        for (int i = 1; i <= theRepNum; i++) {
                            int repIndex = theSourceMessage.indexOf(repSep, currentRange.getStart());
                            if (repIndex == -1) {
                                if (i == theRepNum) {
                                    currentRange = new Range(currentRange.getStart(), nextSeparatorIndex);
                                } else {
                                    // rep is beyond what the message actually
                                    // has.. this probably shouldn't happen
                                    return new Range(currentRange.getEnd(), currentRange.getEnd());
                                }
                            } else if (i == theRepNum) {
                                currentRange = new Range(currentRange.getStart(), repIndex);
                            } else {
                                currentRange = new Range(repIndex + 1, currentRange.getEnd());
                            }
                        }
                    } else {

                        currentRange = new Range(currentRange.getStart(), nextSeparatorIndex);

                    }
                }

                offset--;

                if (ourLog.isDebugEnabled()) {
                    String applyTo = currentRange.applyTo(theSourceMessage);
                    ourLog.debug("New range is " + applyTo + " (" + applyTo.length() + " chars)");
                }

            }
            componentPathIndex++;

            if (ourLog.isDebugEnabled()) {
                String applyTo = currentRange.applyTo(theSourceMessage);
                ourLog.debug("New range is " + applyTo + " (" + applyTo.length() + " chars)");
            }

        }
        return currentRange;
    }

}