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

org.opencds.cqf.tooling.library.LibraryProcessor Maven / Gradle / Ivy

package org.opencds.cqf.tooling.library;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import com.google.common.base.Strings;

import org.apache.commons.io.FilenameUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.Attachment;
import org.hl7.fhir.r5.model.Library;
import org.hl7.fhir.r5.model.RelatedArtifact;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.opencds.cqf.tooling.library.r4.R4LibraryProcessor;
import org.opencds.cqf.tooling.library.stu3.STU3LibraryProcessor;
import org.opencds.cqf.tooling.parameter.RefreshLibraryParameters;
import org.opencds.cqf.tooling.processor.*;
import org.opencds.cqf.tooling.utilities.IOUtils;
import org.opencds.cqf.tooling.utilities.IOUtils.Encoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.opencds.cqf.tooling.utilities.LogUtils;
import org.opencds.cqf.tooling.utilities.ResourceUtils;

import ca.uhn.fhir.context.FhirContext;

public class LibraryProcessor extends BaseProcessor {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    public static final String ResourcePrefix = "library-";   
    public static String getId(String baseId) {
        return ResourcePrefix + baseId;
    }
    private static Pattern pattern;

    private static Pattern getPattern() {
        if(pattern == null) {
            String regex = "^[a-zA-Z]+[a-zA-Z0-9_\\-\\.]*";
            pattern = Pattern.compile(regex);
        }
        return pattern;
    }

    public static void validateIdAlphaNumeric(String id) {
        if(!getPattern().matcher(id).find()) {
            throw new RuntimeException("The library id format is invalid.");
        }
    }
    
    public List refreshIgLibraryContent(BaseProcessor parentContext, Encoding outputEncoding, Boolean versioned, FhirContext fhirContext, Boolean shouldApplySoftwareSystemStamp) {
        return refreshIgLibraryContent(parentContext, outputEncoding, null, null, versioned, fhirContext, shouldApplySoftwareSystemStamp);
    }

    public List refreshIgLibraryContent(BaseProcessor parentContext, Encoding outputEncoding, String libraryOutputDirectory, Boolean versioned, FhirContext fhirContext, Boolean shouldApplySoftwareSystemStamp) {
        return refreshIgLibraryContent(parentContext, outputEncoding, null, libraryOutputDirectory, versioned, fhirContext, shouldApplySoftwareSystemStamp);
    }
    public List refreshIgLibraryContent(BaseProcessor parentContext, Encoding outputEncoding, String libraryPath, String libraryOutputDirectory, Boolean versioned, FhirContext fhirContext, Boolean shouldApplySoftwareSystemStamp) {
        System.out.println("Refreshing libraries...");
        // ArrayList refreshedLibraryNames = new ArrayList();

        LibraryProcessor libraryProcessor;
        switch (fhirContext.getVersion().getVersion()) {
            case DSTU3:
                libraryProcessor = new STU3LibraryProcessor();
                break;
            case R4:
                libraryProcessor = new R4LibraryProcessor();
                break;
            default:
                throw new IllegalArgumentException(
                        "Unknown fhir version: " + fhirContext.getVersion().getVersion().getFhirVersionString());
        }

        if (libraryPath == null) {
            libraryPath = FilenameUtils.concat(parentContext.getRootDir(), IGProcessor.libraryPathElement);
        }
        else if (!Utilities.isAbsoluteFileName(libraryPath)) {
            libraryPath = FilenameUtils.concat(parentContext.getRootDir(), libraryPath);
        }
        RefreshLibraryParameters params = new RefreshLibraryParameters();
        if (Strings.isNullOrEmpty(libraryOutputDirectory)) {
            logger.info("No output directory found for libraries.  Any existing libraries will be overwritten.");
        } else {
            params.libraryOutputDirectory = libraryOutputDirectory;
        }
        params.libraryPath = libraryPath;
        params.parentContext = parentContext;
        params.fhirContext = fhirContext;
        params.encoding = outputEncoding;
        params.versioned = versioned;
        params.shouldApplySoftwareSystemStamp = shouldApplySoftwareSystemStamp;
        return libraryProcessor.refreshLibraryContent(params);
    }

    public Boolean bundleLibraryDependencies(String path, FhirContext fhirContext, Map resources,
            Encoding encoding, boolean versioned) {
        String fileName = FilenameUtils.getName(path);
        boolean prefixed = fileName.toLowerCase().startsWith("library-");
        Boolean shouldPersist = true;
        try {
            Map dependencies = ResourceUtils.getDepLibraryResources(path, fhirContext, encoding, versioned, logger);
            // String currentResourceID = IOUtils.getTypeQualifiedResourceId(path, fhirContext);
            for (IBaseResource resource : dependencies.values()) {
                resources.putIfAbsent(resource.getIdElement().getIdPart(), resource);

                // NOTE: Assuming dependency library will be in directory of dependent.
                String dependencyPath = IOUtils.getResourceFileName(IOUtils.getResourceDirectory(path), resource, encoding, fhirContext, versioned, prefixed);
                bundleLibraryDependencies(dependencyPath, fhirContext, resources, encoding, versioned);
            }
        } catch (Exception e) {
            shouldPersist = false;
            LogUtils.putException(path, e);
        }
        return shouldPersist;
    }

    protected boolean versioned;

    /*
    Refreshes generated content in the given library.
    The name element of the library resource is used to find the cql file (filename = .cql)
    The CqlProcessor is used to get the CqlSourceFileInformation
    Sets
        * cqlContent
        * elmXmlContent
        * elmJsonContent
        * dataRequirements
        * relatedArtifacts
        * parameters

     Does not set publisher-level information (id, name, url, version, publisher, contact, jurisdiction)
     Does not generate narrative
     */
    protected Library refreshGeneratedContent(Library sourceLibrary) {
        String libraryName = sourceLibrary.getName();
        if (versioned) {
            libraryName += "-" + sourceLibrary.getVersion();
        }
        String fileName = libraryName + ".cql";
        Attachment attachment = null;
        try {
            attachment = loadFile(fileName);
        } catch (IOException e) {
            logMessage(String.format("Error loading CQL source for library %s", libraryName));
            e.printStackTrace();
        }

        if (attachment != null) {
            sourceLibrary.getContent().clear();
            sourceLibrary.getContent().add(attachment);
            setLibraryType(sourceLibrary);
            CqlProcessor.CqlSourceFileInformation info = getCqlProcessor().getFileInformation(attachment.getUrl());
            attachment.setUrlElement(null);
            if (info != null) {
                //f.getErrors().addAll(info.getErrors());
                if (info.getElm() != null) {
                    sourceLibrary.addContent().setContentType("application/elm+xml").setData(info.getElm());
                }
                if (info.getJsonElm() != null) {
                    sourceLibrary.addContent().setContentType("application/elm+json").setData(info.getJsonElm());
                }
                sourceLibrary.getDataRequirement().clear();
                sourceLibrary.getDataRequirement().addAll(info.getDataRequirements());
                sourceLibrary.getRelatedArtifact().removeIf(n -> n.getType() == RelatedArtifact.RelatedArtifactType.DEPENDSON);
                sourceLibrary.getRelatedArtifact().addAll(info.getRelatedArtifacts());
                sourceLibrary.getParameter().clear();
                sourceLibrary.getParameter().addAll(info.getParameters());
            } else {
                logMessage(String.format("No cql info found for ", fileName));
                //f.getErrors().add(new ValidationMessage(ValidationMessage.Source.Publisher, ValidationMessage.IssueType.NOTFOUND, "Library", "No cql info found for "+f.getName(), ValidationMessage.IssueSeverity.ERROR));
            }
        }

        return sourceLibrary;
    }

    protected List refreshGeneratedContent(List sourceLibraries) {
        return internalRefreshGeneratedContent(sourceLibraries);
    }

    public List refreshGeneratedContent(String cqlDirectoryPath, String fhirVersion) {
        List result = new ArrayList();
        File input = new File(cqlDirectoryPath);
        if (input.exists() && input.isDirectory()) {
            result.add(input.getAbsolutePath());
        }
        setBinaryPaths(result);

        List libraries = new ArrayList();
        return internalRefreshGeneratedContent(libraries);
    }

    private void setLibraryType(Library library) {
        library.setType(new CodeableConcept().addCoding(
                new Coding().setCode("logic-library")
                        .setSystem("http://terminology.hl7.org/CodeSystem/library-type")));
    }

    private List internalRefreshGeneratedContent(List sourceLibraries) {
        getCqlProcessor().execute();

        // For each CQL file, ensure that there is a Library resource with a matching name and version
        for (CqlProcessor.CqlSourceFileInformation fileInfo : getCqlProcessor().getAllFileInformation()) {
            if (fileInfo.getIdentifier() != null && fileInfo.getIdentifier().getId() != null && !fileInfo.getIdentifier().getId().equals("")) {
                Library existingLibrary = null;
                for (Library sourceLibrary : sourceLibraries) {
                    if (fileInfo.getIdentifier().getId().equals(sourceLibrary.getName())
                            && (fileInfo.getIdentifier().getVersion() == null || fileInfo.getIdentifier().getVersion().equals(sourceLibrary.getVersion()))
                    ) {
                        existingLibrary = sourceLibrary;
                        break;
                    }
                }

                if (existingLibrary == null) {
                    Library newLibrary = new Library();
                    newLibrary.setName(fileInfo.getIdentifier().getId());
                    newLibrary.setVersion(fileInfo.getIdentifier().getVersion());
                    newLibrary.setUrl(String.format("%s/Library/%s", (newLibrary.getName().equals("FHIRHelpers") ? "http://hl7.org/fhir" : canonicalBase), fileInfo.getIdentifier().getId()));
                    newLibrary.setId(newLibrary.getName() + (versioned ? "-" + newLibrary.getVersion() : ""));
                    setLibraryType(newLibrary);
                    validateIdAlphaNumeric(newLibrary.getId());
                    List attachments = new ArrayList();
                    Attachment attachment = new Attachment();
                    attachment.setContentType("application/elm+xml");
                    attachment.setData(fileInfo.getElm());
                    attachments.add(attachment);
                    newLibrary.setContent(attachments);
                    sourceLibraries.add(newLibrary);
                }
            }
        }

        List resources = new ArrayList();
        for (Library library : sourceLibraries) {
            resources.add(refreshGeneratedContent(library));
        }
        return resources;
    }

    private Attachment loadFile(String fn) throws IOException {
        for (String dir : getBinaryPaths()) {
            File f = new File(Utilities.path(dir, fn));
            if (f.exists()) {
                Attachment att = new Attachment();
                att.setContentType("text/cql");
                att.setData(TextFile.fileToBytes(f));
                att.setUrl(f.getAbsolutePath());
                return att;
            }
        }
        return null;
    }

    public List refreshLibraryContent(RefreshLibraryParameters params) {
        return new ArrayList();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy