001package ca.uhn.fhir.cql.common.evaluation;
002
003/*-
004 * #%L
005 * HAPI FHIR JPA Server - Clinical Quality Language
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.i18n.Msg;
024import org.apache.commons.lang3.Validate;
025import org.cqframework.cql.cql2elm.CqlTranslator;
026import org.cqframework.cql.cql2elm.CqlTranslatorException;
027import org.cqframework.cql.cql2elm.CqlTranslatorOptions;
028import org.cqframework.cql.cql2elm.LibraryManager;
029import org.cqframework.cql.cql2elm.ModelManager;
030import org.cqframework.cql.elm.execution.Library;
031import org.cqframework.cql.elm.execution.VersionedIdentifier;
032
033import javax.xml.bind.JAXBException;
034import java.io.ByteArrayInputStream;
035import java.nio.charset.StandardCharsets;
036import java.util.ArrayList;
037import java.util.Collection;
038import java.util.HashMap;
039import java.util.Map;
040
041import static ca.uhn.fhir.cql.common.helper.TranslatorHelper.errorsToString;
042import static ca.uhn.fhir.cql.common.helper.TranslatorHelper.getTranslator;
043import static ca.uhn.fhir.cql.common.helper.TranslatorHelper.readLibrary;
044
045public class LibraryLoader implements org.opencds.cqf.cql.engine.execution.LibraryLoader {
046        private LibraryManager libraryManager;
047        private ModelManager modelManager;
048        private Map<String, Library> libraries = new HashMap<>();
049
050        // private static final Logger logger =
051        // LoggerFactory.getLogger(LibraryLoader.class);
052
053        public Collection<Library> getLibraries() {
054                return this.libraries.values();
055        }
056
057        public LibraryManager getLibraryManager() {
058                return this.libraryManager;
059        }
060
061        public ModelManager getModelManager() {
062                return this.modelManager;
063        }
064
065        public LibraryLoader(LibraryManager libraryManager, ModelManager modelManager) {
066                this.libraryManager = libraryManager;
067                this.modelManager = modelManager;
068        }
069
070        private Library resolveLibrary(VersionedIdentifier libraryIdentifier) {
071                Validate.notNull(libraryIdentifier, "Library identifier is null.");
072
073                Validate.notNull(libraryIdentifier.getId(), "Library identifier id is null.");
074
075                String mangledId = this.mangleIdentifer(libraryIdentifier);
076
077                Library library = libraries.get(mangledId);
078                if (library == null) {
079                        library = loadLibrary(libraryIdentifier);
080                        libraries.put(mangledId, library);
081                }
082
083                return library;
084        }
085
086        private String mangleIdentifer(VersionedIdentifier libraryIdentifier) {
087                String id = libraryIdentifier.getId();
088                String version = libraryIdentifier.getVersion();
089
090                return version == null ? id : id + "-" + version;
091        }
092
093        private Library loadLibrary(VersionedIdentifier libraryIdentifier) {
094                org.hl7.elm.r1.VersionedIdentifier identifier = new org.hl7.elm.r1.VersionedIdentifier()
095                        .withId(libraryIdentifier.getId()).withSystem(libraryIdentifier.getSystem())
096                        .withVersion(libraryIdentifier.getVersion());
097
098                ArrayList<CqlTranslatorException> errors = new ArrayList<>();
099                org.hl7.elm.r1.Library translatedLibrary = libraryManager.resolveLibrary(identifier, CqlTranslatorOptions.defaultOptions(), errors).getLibrary();
100
101                if (CqlTranslatorException.HasErrors(errors)) {
102                        throw new IllegalArgumentException(Msg.code(1657) + errorsToString(errors));
103                }
104                try {
105                        CqlTranslator translator = getTranslator("", libraryManager, modelManager);
106
107                        if (translator.getErrors().size() > 0) {
108                                throw new IllegalArgumentException(Msg.code(1658) + errorsToString(translator.getErrors()));
109                        }
110
111                        return readLibrary(new ByteArrayInputStream(
112                                translator.convertToXml(translatedLibrary).getBytes(StandardCharsets.UTF_8)));
113                } catch (JAXBException e) {
114                        throw new IllegalArgumentException(Msg.code(1659) + String.format("Errors occurred translating library %s%s.",
115                                identifier.getId(), identifier.getVersion() != null ? ("-" + identifier.getVersion()) : ""));
116                }
117        }
118
119        @Override
120        public Library load(VersionedIdentifier versionedIdentifier) {
121                return resolveLibrary(versionedIdentifier);
122        }
123}