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

io.github.linuxforhealth.hl7.util.ExpressionUtility Maven / Gradle / Ivy

Go to download

FHIR converter is a Java based library that enables converting Hl7v2 messages to FHIR resources

There is a newer version: 1.0.19
Show newest version
/*
 * (C) Copyright IBM Corp. 2020, 2021
 *
 * SPDX-License-Identifier: Apache-2.0
 */
package io.github.linuxforhealth.hl7.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.github.linuxforhealth.api.EvaluationResult;
import io.github.linuxforhealth.api.Expression;
import io.github.linuxforhealth.api.InputDataExtractor;
import io.github.linuxforhealth.api.ResourceValue;
import io.github.linuxforhealth.core.Constants;
import io.github.linuxforhealth.core.ObjectMapperUtil;
import io.github.linuxforhealth.core.exception.DataExtractionException;
import io.github.linuxforhealth.core.exception.RequiredConstraintFailureException;
import io.github.linuxforhealth.core.expression.EmptyEvaluationResult;
import io.github.linuxforhealth.core.expression.EvaluationResultFactory;
import io.github.linuxforhealth.hl7.message.HL7MessageData;
import io.github.linuxforhealth.hl7.resource.PendingExpressionState;
import io.github.linuxforhealth.hl7.resource.ResourceEvaluationResult;

public class ExpressionUtility {

    private static final String KEY_NAME_SUFFIX = "KEY_NAME_SUFFIX";

    private static final String EVALUATING = "Evaluating {} {}";

    private static final Logger LOGGER = LoggerFactory.getLogger(ExpressionUtility.class);

    private ExpressionUtility() {
    }

    /**
     * Evaluates map of expression and generates ResourceEvaluationResult object.
     * 
     * @param dataSource The data extractor to be used
     * @param context The context in use
     * @param baseValue The value to evaluate
     * @param expressionMap Map of expressions
     * @return {@link ResourceEvaluationResult}
     */
    public static ResourceEvaluationResult evaluate(InputDataExtractor dataSource,
            Map context, EvaluationResult baseValue,
            Map expressionMap) {

        try {
            Map expressionsToEvaluateLater = new HashMap<>();
            Map localContext = new HashMap<>(context);
            localContext.put(Constants.NULL_VAR_NAME, new EmptyEvaluationResult());
            // initialize the map and list to collect values
            List additionalResolveValues = new ArrayList<>();
            Map resolveValues = new HashMap<>();

            for (Entry entry : expressionMap.entrySet()) {

                Expression exp = entry.getValue();
                
                if (exp.isEvaluateLater()) {
                    expressionsToEvaluateLater.put(entry.getKey(), entry.getValue());
                } else {
                    processExpression(dataSource, baseValue, localContext, additionalResolveValues,
                            resolveValues, entry);
                }
            }
            resolveValues.values().removeIf(Objects::isNull);
            return new ResourceEvaluationResult(resolveValues, additionalResolveValues,
                    new PendingExpressionState(expressionsToEvaluateLater, context));

        } catch (RequiredConstraintFailureException e) {
            LOGGER.warn("Resource Constraint condition not satisfied.");
            
            return null;

        } catch (IllegalArgumentException | IllegalStateException | DataExtractionException e) {
            LOGGER.error("Exception during resource evaluation");
            
            return null;

        }

    }

    private static void processExpression(InputDataExtractor dataSource, EvaluationResult baseValue,
            Map localContext, List additionalResolveValues,
            Map resolveValues, Entry entry) {
        EvaluationResult obj = entry.getValue().evaluate(dataSource, localContext, baseValue);
        

        if (obj != null && !obj.isEmpty()) {
            String keyNameSuffix = getKeyNameSuffix(localContext);
            // Check if the key already exist in the HashMap, if found append, do not replace
            if (!resolveValues.containsKey(getKeyName(entry.getKey(), keyNameSuffix))) {
                resolveValues.put(getKeyName(entry.getKey(), keyNameSuffix), obj.getValue());
            } else {
                Object existing = resolveValues.get(getKeyName(entry.getKey(), keyNameSuffix));
                if (existing instanceof List) {
                    if (obj.getValue() instanceof List) {
                        ((List) existing).addAll(obj.getValue());
                    } else {
                        ((List) existing).add(obj.getValue());
                    }
                }
            }

            if (obj.getAdditionalResources() != null && !obj.getAdditionalResources().isEmpty()
                    && additionalResolveValues != null) {
                additionalResolveValues.addAll(obj.getAdditionalResources());
            }
        }
    }

    private static String getKeyName(String key, String suffix) {
        String[] keyComponents = StringUtils.split(key, "_", 2);
        if (keyComponents.length == 2 && KEY_NAME_SUFFIX.equalsIgnoreCase(keyComponents[1])) {
            return keyComponents[0] + suffix;
        } else {
            return keyComponents[0];
        }

    }

    private static String getKeyNameSuffix(Map localContext) {
        EvaluationResult res = localContext.get(KEY_NAME_SUFFIX);
        if (res == null || res.isEmpty()) {
            return null;
        }
        return res.getValue();
    }

    public static EvaluationResult extractComponent(ImmutablePair fetch,
            EvaluationResult resource) {
        if (resource != null && resource.getValue() instanceof ResourceValue) {
            ResourceValue rv = resource.getValue();
            Map resourceMap = rv.getResource();
            return EvaluationResultFactory.getEvaluationResult(resourceMap.get(fetch.getValue()));
        } else if (resource != null && resource.getValue() instanceof Map) {
            Map resourceMap = (Map) resource.getValue();
            return EvaluationResultFactory.getEvaluationResult(resourceMap.get(fetch.getValue()));
        } else if (resource != null && !resource.isEmpty()) {
            Map resourceMap = ObjectMapperUtil.getJSONInstance().convertValue(resource.getValue(),
                    Map.class);
            return EvaluationResultFactory.getEvaluationResult(resourceMap.get(fetch.getValue()));
        } else {
            return new EmptyEvaluationResult();
        }
    }

    public static ResourceEvaluationResult evaluate(HL7MessageData dataSource,
            Map context, Map expressionMap) {
        try {

            Map localContext = new HashMap<>(context);
            Map resolveValues = new HashMap<>();
            List additionalResolveValues = new ArrayList<>();
            for (Entry entry : expressionMap.entrySet()) {

                

                processExpression(dataSource, new EmptyEvaluationResult(), localContext,
                        additionalResolveValues,
                        resolveValues, entry);

            }
            resolveValues.values().removeIf(Objects::isNull);

            return new ResourceEvaluationResult(resolveValues, additionalResolveValues);

        } catch (RequiredConstraintFailureException e) {
            LOGGER.warn("Resource Constraint condition not satisfied.");
            
            return null;

        } catch (IllegalArgumentException | IllegalStateException | DataExtractionException e) {
            LOGGER.error("Exception during resource evaluation.");
            
            return null;

        }
    }

}