us.conxio.hl7.hl7service.Operand.java Source code

Java tutorial

Introduction

Here is the source code for us.conxio.hl7.hl7service.Operand.java

Source

/*
 *  $Id$
 *
 *  This code is derived from public domain sources. Commercial use is allowed.
 *  However, all rights remain permanently assigned to the public domain.
 *
 *  HL7MessageTransformOperation.java : A class for the atomic operations of HL7
 *                                      message transforms.
 *
 *  Copyright (c) 2009, 2010  Scott Herman
 *
 *  This is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This code is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this code.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package us.conxio.hl7.hl7service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.io.FileNotFoundException;
import java.io.IOException;

import java.net.URI;
import java.net.URISyntaxException;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

import org.apache.log4j.Logger;

import org.w3c.dom.Node;

import us.conxio.XMLUtilities.AttributeMap;
import us.conxio.hl7.hl7message.HL7Designator;
import us.conxio.hl7.hl7message.HL7Message;
import us.conxio.hl7.hl7system.HL7Logger;

/**
 * A polymorphic container class for the argument items of HL7 transform operations. <ul>It contains two strings;
 * <li>a type identifier string. <li>a value string.</ul>
 */
class Operand {
    String type, value;

    public Operand() {
    }

    public Operand(String typeStr, String valueStr) {
        type = typeStr;
        value = valueStr;
    } // Operand

    String dumpString() {
        return "Operand:" + type + ", " + value;
    } // Dump

    boolean isType(String name) {
        if (StringUtils.isEmpty(name))
            return false;
        return type.equalsIgnoreCase(name);
    } // isType
} // Operand

/**
 * A class for the atomic operations of HL7 transforms.
 * Each operation is specified by a separate xml entity,
 * <ul>and contains
 * <li>a name. (String)
 * <li>a resultant HL7 item designation. (String)
 * <li>a list of operands.</ul>
 * @author scott
 */
public class HL7MessageTransformOperation {
    private String opName;
    private String resultDesignator;
    private Method method = null;
    private Pattern opPattern;
    private TranslationTable xlateTable = null;
    private URI resourceURI = null;

    ArrayList<Operand> operands = null;
    private static Logger logger = HL7Logger.getHL7Logger();

    public static final String OPERAND_TYPE_STRING = "string";
    public static final String OPERAND_TYPE_SEARCH = "search";
    public static final String OPERAND_TYPE_DESIGNATOR = "designator";
    public static final String OPERAND_TYPE_RESOURCE = "resource-uri";

    public static final String OPERATION_NAME_QUALIFY = "qualify";
    public static final String OPERATION_NAME_EXCLUDE = "exclude";

    // constructors
    public HL7MessageTransformOperation() {
    }

    public HL7MessageTransformOperation(String name, String designator) {
        opName = name;
        resultDesignator = designator;
        setMethod();
    } // HL7MessageTransformOperation

    public HL7MessageTransformOperation(String name, String designator, String operandType, String operandValue) {
        opName = name;
        resultDesignator = designator;
        setMethod();
        _addOperand(new Operand(operandType, operandValue));
    } // HL7MessageTransformOperation

    /**
     * Constructs a HL7MessageTransformOperation for the argument xml Node.
     * @param node The node from which to construct the object.
     * @throws IOException If the file is not found, or is not properly formatted.
     */
    public HL7MessageTransformOperation(Node node) throws IOException {
        opName = node.getNodeName().toLowerCase();
        if (!haveThisMethod()) {
            logger.error("Not a valid method:" + opName);
            return;
        } // if

        if (node.hasAttributes()) {
            AttributeMap attributes = new AttributeMap(node);
            if (attributes.hasKey(OPERAND_TYPE_DESIGNATOR)) {
                resultDesignator = attributes.get(OPERAND_TYPE_DESIGNATOR);
            } // if

            if (attributes.hasKey(OPERAND_TYPE_SEARCH)) {
                _addOperand(new Operand(OPERAND_TYPE_SEARCH, attributes.get(OPERAND_TYPE_SEARCH)));
            } // if

            if (attributes.hasKey(OPERAND_TYPE_RESOURCE)) {
                initializeMap(attributes.get(OPERAND_TYPE_RESOURCE));
            } // if
        } // if

        String nodeText = node.getTextContent();
        if (StringUtils.isNotEmpty(nodeText)) {
            String[] operandsArray = nodeText.split(", ?", -2);
            int opsLength = operandsArray.length;
            for (int index = 0; index < opsLength; ++index) {
                _addOperand(new Operand(OPERAND_TYPE_STRING, operandsArray[index]));
            } // for
        } // if
    } // HL7MessageTransformOperation

    private void _addOperand(Operand operand) {
        if (operands == null)
            operands = new ArrayList<Operand>();
        operands.add(operand);
    } // _addOperand

    void addOperand(Operand operand) {
        _addOperand(operand);
    }

    /**
     * Add an operand to the context operation.
     * @param typeStr A String representation of the operand type
     * @param valueStr A String representation of the operand value.
     * @return The context HL7MessageTransformOperation object.
     */
    public HL7MessageTransformOperation addOperand(String typeStr, String valueStr) {
        addOperand(new Operand(typeStr, valueStr));
        return this;
    } // addOperand

    void dump() {
        logger.debug("HL7Operation name:" + getOpName() + ", ResultDesignator:" + getResultDesignator());
        for (Operand operand : operands)
            logger.debug(operand.dumpString());
    } // dump

    private void initializeMap(String uriStr) throws FileNotFoundException, IOException {
        try {
            resourceURI = new URI(uriStr);
        } catch (URISyntaxException ex) {
            throw new IllegalArgumentException(ex);
        } // try - catch

        if (!resourceURI.getScheme().equalsIgnoreCase("file")) {
            throw new IllegalArgumentException("URI schemes other than file/// not handled.");
        } // if

        xlateTable = loadTranslationTable();
    } // initializeMap

    private TranslationTable loadTranslationTable() throws FileNotFoundException, IOException {
        return TranslationTable.make(resourceURI);
    } // loadTranslationTable

    // Operation handlers:

    boolean qualify(HL7Message msg) {
        if (!hasPattern() && hasStringOperandAt(0))
            opPattern = Pattern.compile(stringOperandValueAt(0));
        return messageMatches(msg);
    } // qualify

    boolean exclude(HL7Message msg) {
        if (!hasPattern() && hasStringOperandAt(0))
            opPattern = Pattern.compile(stringOperandValueAt(0));
        return messageMatches(msg);
    } // exclude

    private boolean messageMatches(HL7Message msg) {
        if (!hasDesignator())
            return false;
        if (opPattern == null)
            return false;
        String subject = msg.get(resultDesignator);
        if (StringUtils.isEmpty(subject))
            return false;
        return opPattern.matcher(subject).matches();
    } // messageMatches

    boolean assign(HL7Message msg) {
        if (hasDesignator() && hasStringOperandAt(0)) {
            msg.set(resultDesignator, stringOperandValueAt(0));
            return true;
        } // if

        return false;
    } // assign

    boolean newsegment(HL7Message msg) {
        String segStr = null;
        String arg = stringOperandValueAt(0);
        if (hasDesignator() && resultDesignator.length() > 2) {
            segStr = resultDesignator.substring(0, 3);
        } // if

        if (StringUtils.isNotEmpty(segStr) && StringUtils.isNotEmpty(arg) && arg.length() > segStr.length()) {
            segStr = arg;
        } // if

        if (StringUtils.isEmpty(segStr))
            segStr = arg;
        if (StringUtils.isEmpty(segStr) || segStr.length() < 3)
            return false;

        msg.addSegment(segStr);
        return true;
    } // newsegment

    /**
     * Re-evaluate wild card segment index to refer to the last segment.
     * @param designatorStr
     * @param msg
     * @return
     */
    private String selectLastSegmentOfWildCard(String designatorStr, HL7Message msg) {
        String returnStr = designatorStr;
        HL7Designator hl7Designator = new HL7Designator(designatorStr);
        if (hl7Designator.getSegIndex() <= 0) {
            hl7Designator.setSegIndex(msg.countSegment(hl7Designator.getSegID()) - 1);
            returnStr = hl7Designator.toString();
        } // if

        return returnStr;
    } // selectLastSegmentOfWildCard

    boolean appoint(HL7Message msg) {
        if (hasDesignator() && hasStringOperandAt(0)) {
            msg.set(selectLastSegmentOfWildCard(resultDesignator, msg), stringOperandValueAt(0));
            return true;
        } // if

        return false;
    } // appoint

    boolean swap(HL7Message msg) {
        if (!hasStringOperandAt(0) || !hasStringOperandAt(1))
            return false;
        msg.swap(stringOperandValueAt(0), stringOperandValueAt(1));
        return (true);
    } // swap

    boolean replace(HL7Message msg) {
        if (!hasDesignator())
            return false;
        String subject = msg.get(resultDesignator);
        if (StringUtils.isEmpty(subject))
            return false;

        String replacement = null;

        for (Operand op : operands) {
            if (op.isType(OPERAND_TYPE_SEARCH)) {
                if (!hasPattern() && StringUtils.isNotEmpty(op.value)) {
                    opPattern = Pattern.compile(op.value);
                } // if
            } else {
                replacement = op.value;
            } // if - else
        } // for

        if (!hasPattern())
            return false;
        if (replacement == null)
            replacement = "";

        Matcher matcher = opPattern.matcher(subject);
        String result = matcher.replaceAll(replacement);

        /* Note that regex search and replace only occurs when
         *  - the subject (destination) is not empty
         *  - the search string is not empty
         * In all other situations the specified replacement is assigned to the designated item (destination).
         */
        if (result == null)
            result = replacement;

        msg.set(resultDesignator, result);
        return true;
    } // replace

    boolean scrub(HL7Message msg) {
        if (!hasDesignator())
            return false;

        String toBeScrubbed = msg.get(resultDesignator);
        if (StringUtils.isNotEmpty(toBeScrubbed)) {
            String replUCAlpha = toBeScrubbed.replaceAll("[A-Z]", "X");
            String replLCAlpha = replUCAlpha.replaceAll("[a-z]", "x");
            String replDigits = replLCAlpha.replaceAll("[0-9]", "9");
            msg.set(resultDesignator, replDigits);
            return true;
        } // if

        return false;
    } // scrub

    boolean copy(HL7Message msg) {
        if (!hasDesignator())
            return false;

        String fromDesignator = null;
        if (hasStringOperandAt(0) || hasDesignatorOperandAt(0)) {
            fromDesignator = operands.get(0).value;
        } // if

        if (StringUtils.isEmpty(fromDesignator))
            return false;

        String subject = msg.get(fromDesignator);
        msg.set(resultDesignator, subject);

        return (true);
    } // copy

    boolean remove(HL7Message msg) {
        if (!hasDesignator())
            return false;
        msg.remove(resultDesignator);
        return (true);
    } // remove

    boolean translate(HL7Message msg) throws FileNotFoundException, IOException {
        if (!hasDesignator())
            return false;

        String subject = null;
        if (hasStringOperandAt(0))
            subject = stringOperandValueAt(0);
        if (StringUtils.isEmpty(subject))
            subject = msg.get(resultDesignator);
        if (StringUtils.isEmpty(subject))
            return false;

        String replacement = null;
        if (!hasTranslationTable())
            xlateTable = loadTranslationTable();
        if (!hasTranslationTable())
            return false;

        replacement = xlateTable.get(subject);
        msg.set(resultDesignator, replacement);
        return true;
    } // translate

    // operation "aliases"

    boolean isQualified(HL7Message msg) {
        if (opName.equalsIgnoreCase(OPERATION_NAME_QUALIFY))
            return qualify(msg);
        if (opName.equalsIgnoreCase(OPERATION_NAME_EXCLUDE))
            return !exclude(msg);
        return false;
    } // isQualified

    HL7Message transform(HL7Message msg) {
        if (msg == null)
            return null;

        if (!hasMethod())
            setMethod();
        try {
            Object retnObj = method.invoke(this, msg);
            return ((Boolean) retnObj).booleanValue() ? msg : null;
        } catch (IllegalAccessException ex) {
            logger.error(null, ex);
        } catch (IllegalArgumentException ex) {
            logger.error(null, ex);
        } catch (InvocationTargetException ex) {
            logger.error(null, ex);
        } // try - catch

        return null;
    } // transform

    private void setMethod() {
        Class parms[] = { HL7Message.class };
        try {
            method = getClass().getDeclaredMethod(getOpName().toLowerCase(), parms);
        } catch (NoSuchMethodException ex) {
            logger.error("opName:" + getOpName(), ex);
        } catch (SecurityException ex) {
            logger.error("opName:" + getOpName(), ex);
        } // try - catch
    } // setMethod

    private boolean hasMethod() {
        return method != null;
    } //hasMethod

    /**
     * @return the opName
     */
    public String getOpName() {
        return opName;
    }

    /**
     * @param opName the opName to set
     */
    public void setOpName(String opNameStr) {
        opName = opNameStr;
    }

    /**
     * @return the resultDesignator
     */
    public String getResultDesignator() {
        return resultDesignator;
    }

    /**
     * @param resultDesignator the resultDesignator to set
     */
    public void setResultDesignator(String rltDesignator) {
        resultDesignator = rltDesignator;
    }

    private boolean hasOperand(int index) {
        return hasOperands() && operands.size() > index;
    } // hasOperand

    private boolean hasOperands() {
        return operands != null && !operands.isEmpty();
    } // hasOperands

    private boolean hasStringOperandAt(int index) {
        return hasTypeOperandAt(OPERAND_TYPE_STRING, index);
    } // hasStringOperandAt

    private String stringOperandValueAt(int index) {
        return (hasStringOperandAt(index)) ? operands.get(index).value : null;
    } // stringOperandValueAt

    private boolean hasPattern() {
        return opPattern != null;
    } // hasPattern

    private boolean hasDesignatorOperandAt(int index) {
        return hasTypeOperandAt(OPERAND_TYPE_DESIGNATOR, index);
    } // hasDesignatorOperandAt

    private boolean hasTypeOperandAt(String typeStr, int index) {
        return hasOperand(index) && operands.get(index).isType(typeStr)
                && StringUtils.isNotEmpty(operands.get(index).value);
    } // hasTypeOperandAt

    private boolean hasDesignator() {
        return StringUtils.isNotEmpty(resultDesignator);
    } // hasDesignator

    private boolean haveThisMethod() {
        Class parms[] = { HL7Message.class };
        try {
            method = getClass().getDeclaredMethod(opName.toLowerCase(), parms);
            return true;
        } catch (NoSuchMethodException ex) {
            return false;
        } catch (SecurityException ex) {
            return false;
        } // try - catch
    } // haveThisMethod

    public static boolean haveMethod(String name) {
        Class parms[] = { HL7Message.class };
        try {
            HL7MessageTransformOperation.class.getDeclaredMethod(name.toLowerCase(), parms);
            return true;
        } catch (NoSuchMethodException ex) {
            return false;
        } catch (SecurityException ex) {
            return false;
        } // try - catch
    }

    boolean isQualificationOperation() {
        return opName.equalsIgnoreCase(OPERATION_NAME_QUALIFY) || opName.equalsIgnoreCase(OPERATION_NAME_EXCLUDE);
    } // isQualificationOperation

    private boolean hasTranslationTable() {
        return xlateTable != null && !xlateTable.isEmpty();
    } // hasTranslationTable

} // HL7MessageTransformOperation