uk.nhs.cfh.dsp.snomed.converters.human.readable.impl.HeuristicBasedHumanReadableRenderImpl.java Source code

Java tutorial

Introduction

Here is the source code for uk.nhs.cfh.dsp.snomed.converters.human.readable.impl.HeuristicBasedHumanReadableRenderImpl.java

Source

/**
 * Crown Copyright (C) 2008 - 2011
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.nhs.cfh.dsp.snomed.converters.human.readable.impl;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.event.ConfigurationEvent;
import org.apache.commons.configuration.event.ConfigurationListener;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import uk.nhs.cfh.dsp.snomed.converters.human.readable.HumanReadableRender;
import uk.nhs.cfh.dsp.snomed.expression.model.CloseToUserExpression;
import uk.nhs.cfh.dsp.snomed.expression.model.PropertyExpression;
import uk.nhs.cfh.dsp.snomed.expression.model.impl.SnomedRelationshipPropertyExpression;
import uk.nhs.cfh.dsp.snomed.expression.model.impl.SnomedRoleGroupExpression;
import uk.nhs.cfh.dsp.snomed.mrcm.MRCMService;
import uk.nhs.cfh.dsp.snomed.objectmodel.ConceptType;
import uk.nhs.cfh.dsp.snomed.objectmodel.SnomedConcept;
import uk.nhs.cfh.dsp.snomed.objectmodel.SnomedRelationship;
import uk.nhs.cfh.dsp.snomed.objectmodel.impl.SnomedRelationshipImpl;

import java.io.File;
import java.util.*;

// TODO: Auto-generated Javadoc
/**
 * A concrete implementation of a {@link uk.nhs.cfh.dsp.snomed.converters.human.readable.HumanReadableRender}
 * that uses some naive heuristics to render a {@link uk.nhs.cfh.dsp.snomed.expression.model.CloseToUserExpression}
 *
 * @scr.component immediate=true?
 * @scr.service
 * 
 * <br>Version : @#VersionNumber#@
 * <br>Written by @author Jay Kola
 * <br>Created on Jan 27, 2010 at 10:38:03 PM
 */
public class HeuristicBasedHumanReadableRenderImpl extends AbstractHumanReadableRenderer
        implements HumanReadableRender, ConfigurationListener {

    /** The logger. */
    private static Log logger = LogFactory.getLog(HeuristicBasedHumanReadableRenderImpl.class);

    /** The italicise attributes. */
    private boolean italiciseAttributes = true;

    /** The mrcm service. */
    private MRCMService mrcmService;

    /** The Constant FOCUS_CONCEPT. */
    private static final String FOCUS_CONCEPT = "FOCUS_CONCEPT";

    /** The situation ordering list. */
    private List<String> situationOrderingList = new ArrayList<String>();

    /** The finding ordering list. */
    private List<String> findingOrderingList = new ArrayList<String>();

    /** The procedure ordering list. */
    private List<String> procedureOrderingList = new ArrayList<String>();

    /** The human rendering map. */
    private Map<String, String> humanRenderingMap = new HashMap<String, String>();
    private String renderingFileLocation;
    private XMLConfiguration configuration;

    /**
     * Instantiates a new heuristic based human readable render impl.
     *
     * @param mrcmService the mrcm service
     */
    public HeuristicBasedHumanReadableRenderImpl(MRCMService mrcmService) {
        this.mrcmService = mrcmService;
        configuration = new XMLConfiguration();
        configuration.setExpressionEngine(new XPathExpressionEngine());
        // this reload strategy wont work because we don't use the config object directly        
        configuration.setReloadingStrategy(new FileChangedReloadingStrategy());
    }

    /**
     * Empty constructor for IOC.
     */
    public HeuristicBasedHumanReadableRenderImpl() {
        configuration = new XMLConfiguration();
        configuration.setExpressionEngine(new XPathExpressionEngine());
        // this reload strategy wont work because we don't use the config object directly
        configuration.setReloadingStrategy(new FileChangedReloadingStrategy());
    }

    /*
     * this method initialises the parent concepts used by the contexts. This method needs to be
     * called before this object is used.
     */
    /**
     * Intialise collections.
     */
    public synchronized void intialiseCollections() {

        // populate list with standard set of Attributes
        situationOrderingList.add(ConceptType.ATTRIBUTE_FINDING_CONTEXT.getID()); // finding context
        situationOrderingList.add(ConceptType.ATTRIBUTE_TEMPORAL_CONTEXT.getID()); // temporal context
        situationOrderingList.add(ConceptType.ATTRIBUTE_PROCEDURE_CONTEXT.getID()); //  procedure context
        situationOrderingList.add(FOCUS_CONCEPT); //  FOCUS CONCEPT
        situationOrderingList.add(ConceptType.ATTRIBUTE_SUBJECT_RELATIONSHIP_CONTEXT.getID()); // subject relationship context
        //        situationOrderingList.add(ConceptType.ATTRIBUTE_ASSOCIATED_FINDING.getID());  // associated finding
        //        situationOrderingList.add(ConceptType.ATTRIBUTE_ASSOCIATED_PROCEDURE.getID());  // associated procedure

        findingOrderingList.add(ConceptType.ATTRIBUTE_EPISODICITY.getID()); // episodicity
        findingOrderingList.add(ConceptType.ATTRIBUTE_COURSE.getID()); // course
        findingOrderingList.add(ConceptType.ATTRIBUTE_SEVERITIES.getID()); // severities
        findingOrderingList.add(FOCUS_CONCEPT); // FOCUS_CONCEPT
        findingOrderingList.add(ConceptType.ATTRIBUTE_ASSOCIATED_MORPHOLOGY.getID()); // associated morphology
        findingOrderingList.add(ConceptType.ATTRIBUTE_LATERALITY.getID()); // laterality
        findingOrderingList.add(ConceptType.ATTRIBUTE_FINDING_SITE.getID()); // finding site

        procedureOrderingList.add(ConceptType.ATTRIBUTE_PRIORITY.getID()); // priority
        procedureOrderingList.add(ConceptType.ATTRIBUTE_METHOD.getID()); // method
        procedureOrderingList.add(FOCUS_CONCEPT); // FOCUS_CONCEPT
        procedureOrderingList.add(ConceptType.ATTRIBUTE_LATERALITY.getID()); // laterality
        procedureOrderingList.add(ConceptType.ATTRIBUTE_DIRECT_PROCEDURE_SITE.getID()); //direct procedure site
        procedureOrderingList.add(ConceptType.ATTRIBUTE_INDIRECT_PROCEDURE_SITE.getID()); //indirect procedure site
        procedureOrderingList.add(ConceptType.ATTRIBUTE_PROCEDURE_SITE.getID()); //procedure site
        procedureOrderingList.add(ConceptType.ATTRIBUTE_ACCESS.getID()); //access
        procedureOrderingList.add(ConceptType.ATTRIBUTE_SURGICAL_APPROACH.getID()); //surgical approach
        procedureOrderingList.add(ConceptType.ATTRIBUTE_USING_DEVICE.getID()); //using device
        procedureOrderingList.add(ConceptType.ATTRIBUTE_USING_ACCESS_DEVICE.getID()); //using access device
        procedureOrderingList.add(ConceptType.ATTRIBUTE_USING_ENERGY.getID()); //using energy
        procedureOrderingList.add(ConceptType.ATTRIBUTE_USING_SUBSTANCE.getID()); //using substance
    }

    /**
     * update human readable map.
     *
     */
    private void updateHumanRenderingMap() {

        File file = new File(renderingFileLocation);
        logger.info("renderingFileLocation = " + renderingFileLocation);
        if (file.exists() && file.canRead()) {
            try {
                configuration.load(file);
                List fields = configuration.configurationsAt("//rendered_attribute");
                // clear existing map
                humanRenderingMap.clear();

                for (Object field : fields) {
                    HierarchicalConfiguration sub = (HierarchicalConfiguration) field;
                    // sub contains now all data about a single field
                    String attributeId = sub.getString("id");
                    String attributeText = sub.getString("text");

                    // put values in map
                    humanRenderingMap.put(attributeId, attributeText);
                }
                logger.debug("humanRenderingMap = " + humanRenderingMap);
            } catch (ConfigurationException e) {
                logger.warn("Error reading configuration file. Nested exception is : "
                        + e.fillInStackTrace().getMessage());
            }
        } else {
            logger.warn("Error reading file from provided URL.");
            throw new IllegalArgumentException("Error reading file from provided URL.");
        }
    }

    /* (non-Javadoc)
    * @see uk.nhs.cfh.dsp.snomed.converters.human.readable.impl.AbstractHumanReadableRenderer#getHumanReadableLabel(uk.nhs.cfh.dsp.snomed.expression.model.CloseToUserExpression)
    */
    @Override
    protected String getHumanReadableLabel(CloseToUserExpression closeToUserExpression) {
        // get refinements and process them based on rules and priority
        Collection<PropertyExpression> propertyExpressions = closeToUserExpression.getRefinementExpressions();
        SnomedConcept focusConcept = closeToUserExpression.getSingletonFocusConcept();
        ConceptType conceptType = focusConcept.getType();
        boolean associatedConceptPresent = false;
        // create a temporary list object to store all components for ordering and rendering
        List<SnomedRelationshipPropertyExpression> tempList = new ArrayList<SnomedRelationshipPropertyExpression>();

        Set<SnomedRelationshipPropertyExpression> refiningRelationships = new HashSet<SnomedRelationshipPropertyExpression>();
        // get list of sanctioned attributes on focus concept
        Set<String> sanctionedAttributes = mrcmService.getSanctionedAttributes(conceptType);
        // get relationships on all property expressions
        for (PropertyExpression propertyExpression : propertyExpressions) {
            if (propertyExpression instanceof SnomedRelationshipPropertyExpression) {
                SnomedRelationshipPropertyExpression relationshipPropertyExpression = (SnomedRelationshipPropertyExpression) propertyExpression;
                String relationshipType = getRelationshipType(relationshipPropertyExpression);
                // check if relationshipType is associated procedure or finding in a situation
                if (ConceptType.ATTRIBUTE_ASSOCIATED_FINDING.getID().equals(relationshipType)
                        || "".equals(relationshipType)) {
                    associatedConceptPresent = true;
                }

                // check for unsanctioned attributes - but consider laterality
                if (sanctionedAttributes.contains(relationshipType)
                        || ConceptType.ATTRIBUTE_LATERALITY.getID().equals(relationshipType)) {
                    refiningRelationships.add(relationshipPropertyExpression);
                } else {
                    logger.warn("Found unsanctioned relationship type... ignoring");
                }
            } else if (propertyExpression instanceof SnomedRoleGroupExpression) {
                logger.warn("Encountered role group expression... Ignoring the expression");
                getHumanReadableLabel((SnomedRoleGroupExpression) propertyExpression);
            }
        }

        // check if we have processed all refinements
        if (refiningRelationships.size() == propertyExpressions.size()) {
            // add refining relationships to tempList
            tempList.addAll(refiningRelationships);

            // order relationships using comparator and focus concept type
            if (ConceptType.SITUATION_WEC == conceptType || ConceptType.FINDING_WEC == conceptType
                    || ConceptType.PROCEDURE_WEC == conceptType) {
                if (!associatedConceptPresent) {
                    // add focus concept as a relationship
                    addFocusConceptToList(tempList, focusConcept);
                }
                Collections.sort(tempList, new HumanReadablePropertyExpressionComparator(situationOrderingList));
            } else if (ConceptType.FINDING == conceptType || ConceptType.DISEASE == conceptType) {
                // add focus concept as a relationship
                addFocusConceptToList(tempList, focusConcept);
                Collections.sort(tempList, new HumanReadablePropertyExpressionComparator(findingOrderingList));
            } else if (ConceptType.PROCEDURE == conceptType || ConceptType.SURGICAL_PROCEDURE == conceptType
                    || ConceptType.EVALUATION_PROCEDURE == conceptType) {
                // add focus concept as a relationship
                addFocusConceptToList(tempList, focusConcept);
                Collections.sort(tempList, new HumanReadablePropertyExpressionComparator(procedureOrderingList));
            } else {
                addFocusConceptToList(tempList, focusConcept);
            }
        } else {
            logger.warn("Found some property expressions that do not belong to focus concept");
        }

        return getHumanReadableLabel(tempList);
    }

    /**
     * Adds the focus concept to list.
     *
     * @param tempList the temp list
     * @param focusConcept the focus concept
     */
    private void addFocusConceptToList(List<SnomedRelationshipPropertyExpression> tempList,
            SnomedConcept focusConcept) {
        SnomedRelationship r = new SnomedRelationshipImpl();
        r.setRelationshipType("FOCUS_CONCEPT");
        r.setTargetConcept(focusConcept);
        SnomedRelationshipPropertyExpression pe = new SnomedRelationshipPropertyExpression(r);
        // add pe to refiningRelationships
        tempList.add(pe);
    }

    /**
     * Gets the human readable label.
     *
     * @param relationshipPropertyExpressions the relationship property expressions
     * @return the human readable label
     */
    protected String getHumanReadableLabel(
            Collection<SnomedRelationshipPropertyExpression> relationshipPropertyExpressions) {
        String humanReadableString = "";
        int counter = 0;
        for (SnomedRelationshipPropertyExpression p : relationshipPropertyExpressions) {
            if (counter == 0) {
                humanReadableString = getHumanReadableLabel(p);
            } else {
                humanReadableString = humanReadableString + " , " + getHumanReadableLabel(p);
            }

            // increment counter
            counter++;
        }

        return humanReadableString;
    }

    /* (non-Javadoc)
     * @see uk.nhs.cfh.dsp.snomed.converters.human.readable.impl.AbstractHumanReadableRenderer#getHumanReadableLabel(uk.nhs.cfh.dsp.snomed.expression.model.impl.SnomedRelationshipPropertyExpression)
     */
    @Override
    protected String getHumanReadableLabel(SnomedRelationshipPropertyExpression propertyExpression) {
        // get relationship name and use look up map for rendering text
        String relationshipType = getRelationshipType(propertyExpression);
        SnomedConcept targetConcept = propertyExpression.getRelationship().getTargetConcept();
        if (humanRenderingMap.containsKey(relationshipType)) {
            return humanRenderingMap.get(relationshipType) + " " + getHumanReadableLabel(targetConcept);
        } else if (situationOrderingList.contains(relationshipType)
                || findingOrderingList.contains(relationshipType)
                || procedureOrderingList.contains(relationshipType)) {
            return getHumanReadableLabel(targetConcept);
        } else {
            return getHumanReadableLabel(relationshipType) + " of " + getHumanReadableLabel(targetConcept);
        }
    }

    /**
     * Gets the relationship type.
     *
     * @param propertyExpression the property expression
     * @return the relationship type
     */
    private String getRelationshipType(SnomedRelationshipPropertyExpression propertyExpression) {
        if (propertyExpression != null) {
            SnomedRelationship relationship = propertyExpression.getRelationship();
            if (relationship != null) {
                String relationshipType = relationship.getRelationshipType();
                if (relationshipType != null) {
                    return relationshipType;
                } else {
                    throw new IllegalArgumentException("Relationship does not contain a type.");
                }
            } else {
                throw new IllegalArgumentException(
                        "Relationship Expression passed does not contain a relationship");
            }
        } else {
            throw new IllegalArgumentException("Relationship expression passed can not be null.");
        }
    }

    /**
     * Sets the mrcm service.
     *
     * @param mrcmService the new mrcm service
     */
    public synchronized void setMrcmService(MRCMService mrcmService) {
        this.mrcmService = mrcmService;
    }

    /**
     * Checks if is italicise attributes.
     *
     * @return true, if is italicise attributes
     */
    public boolean isItaliciseAttributes() {
        return italiciseAttributes;
    }

    /**
     * Sets the italicise attributes.
     *
     * @param italiciseAttributes the new italicise attributes
     */
    public void setItaliciseAttributes(boolean italiciseAttributes) {
        this.italiciseAttributes = italiciseAttributes;
    }

    public void configurationChanged(ConfigurationEvent event) {
        if (!event.isBeforeUpdate()) {
            // we know that config file has changed, so we update humanRenderingMap
            updateHumanRenderingMap();
        }
    }

    /**
     * The Class HumanReadablePropertyExpressionComparator.
     */
    class HumanReadablePropertyExpressionComparator implements Comparator<SnomedRelationshipPropertyExpression> {

        /** The attributes list. */
        private List<String> attributesList;

        /**
         * Instantiates a new human readable property expression comparator.
         *
         * @param attributesList the attributes list
         */
        HumanReadablePropertyExpressionComparator(List<String> attributesList) {
            this.attributesList = attributesList;
        }

        /* (non-Javadoc)
         * @see java.util.Comparator#compare(T, T)
         */
        public int compare(SnomedRelationshipPropertyExpression r1, SnomedRelationshipPropertyExpression r2) {
            String r1Type = getRelationshipType(r1);
            String r2Type = getRelationshipType(r2);

            if (attributesList.indexOf(r1Type) < attributesList.indexOf(r2Type)) {
                return -1;
            } else if (attributesList.indexOf(r1Type) > attributesList.indexOf(r2Type)) {
                return 1;
            } else {
                return 0;
            }
        }
    }

    public void setRenderingFileLocation(String renderingFileLocation) {
        this.renderingFileLocation = renderingFileLocation;
        // update humanRenderingMap
        updateHumanRenderingMap();
    }
}