package org.opencds.cqf.r4.providers; import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.RequiredParam; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; import ca.uhn.fhir.rest.param.StringAndListParam; import ca.uhn.fhir.rest.param.StringOrListParam; import ca.uhn.fhir.rest.param.StringParam; import org.hl7.fhir.r4.model.*; import org.opencds.cqf.r4.helpers.Helper; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class CacheValueSetsProvider { private IFhirSystemDao systemDao; private IFhirResourceDao<Endpoint> endpointDao; public CacheValueSetsProvider(IFhirSystemDao systemDao, IFhirResourceDao<Endpoint> endpointDao) { this.systemDao = systemDao; this.endpointDao = endpointDao; } @Operation(name="cache-valuesets", idempotent = true, type = Endpoint.class) public Resource cacheValuesets( RequestDetails details, @IdParam IdType theId, @RequiredParam(name="valuesets") StringAndListParam valuesets, @OptionalParam(name="user") String userName, @OptionalParam(name="pass") String password ) { Endpoint endpoint = this.endpointDao.read(theId); if (endpoint == null) { return Helper.createErrorOutcome("Could not find Endpoint/" + theId); } IGenericClient client = this.systemDao.getContext().newRestfulGenericClient(endpoint.getAddress()); if (userName != null || password != null) { if (userName == null) { Helper.createErrorOutcome("Password was provided, but not a user name."); } else if (password == null) { Helper.createErrorOutcome("User name was provided, but not a password."); } BasicAuthInterceptor basicAuth = new BasicAuthInterceptor(userName, password); client.registerInterceptor(basicAuth); // TODO - more advanced security like bearer tokens, etc... } try { Bundle bundleToPost = new Bundle(); for (StringOrListParam params : valuesets.getValuesAsQueryTokens()) { for (StringParam valuesetId : params.getValuesAsQueryTokens()) { bundleToPost.addEntry() .setRequest(new Bundle.BundleEntryRequestComponent().setMethod(Bundle.HTTPVerb.PUT).setUrl("ValueSet/" + valuesetId.getValue())) .setResource(resolveValueSet(client, valuesetId.getValue())); } } return (Resource) systemDao.transaction(details, bundleToPost); } catch (Exception e) { return Helper.createErrorOutcome(e.getMessage()); } } private ValueSet getCachedValueSet(ValueSet expandedValueSet) { ValueSet clean = expandedValueSet.copy().setExpansion(null); Map<String, ValueSet.ConceptSetComponent> concepts = new HashMap<>(); for (ValueSet.ValueSetExpansionContainsComponent expansion : expandedValueSet.getExpansion().getContains()) { if (!expansion.hasSystem()) { continue; } if (concepts.containsKey(expansion.getSystem())) { concepts.get(expansion.getSystem()) .addConcept( new ValueSet.ConceptReferenceComponent() .setCode(expansion.hasCode() ? expansion.getCode() : null) .setDisplay(expansion.hasDisplay() ? expansion.getDisplay() : null) ); } else { concepts.put( expansion.getSystem(), new ValueSet.ConceptSetComponent().setSystem(expansion.getSystem()) .addConcept( new ValueSet.ConceptReferenceComponent() .setCode(expansion.hasCode() ? expansion.getCode() : null) .setDisplay(expansion.hasDisplay() ? expansion.getDisplay() : null) ) ); } } clean.setCompose( new ValueSet.ValueSetComposeComponent() .setInclude(new ArrayList<>(concepts.values())) ); return clean; } private ValueSet resolveValueSet(IGenericClient client, String valuesetId) { ValueSet valueSet = client.fetchResourceFromUrl(ValueSet.class, client.getServerBase() + "/ValueSet/" + valuesetId); boolean expand = false; if (valueSet.hasCompose()) { for (ValueSet.ConceptSetComponent component : valueSet.getCompose().getInclude()) { if (!component.hasConcept() || component.getConcept() == null) { expand = true; } } } if (expand) { return getCachedValueSet( client .operation() .onInstance(new IdType("ValueSet", valuesetId)) .named("$expand") .withNoParameters(Parameters.class) .returnResourceType(ValueSet.class) .execute() ); } valueSet.setVersion(valueSet.getVersion() + "-cache"); return valueSet; } }