001/*- 002 * #%L 003 * HAPI FHIR Storage api 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.validation; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.context.support.IValidationSupport; 024import ca.uhn.fhir.i18n.Msg; 025import ca.uhn.fhir.jpa.api.dao.DaoRegistry; 026import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; 027import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; 028import ca.uhn.fhir.rest.api.server.RequestDetails; 029import ca.uhn.fhir.rest.param.TokenParam; 030import ca.uhn.fhir.rest.param.UriParam; 031import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 032import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; 033import org.hl7.fhir.common.hapi.validation.validator.VersionSpecificWorkerContextWrapper; 034import org.hl7.fhir.exceptions.FHIRException; 035import org.hl7.fhir.instance.model.api.IBaseResource; 036import org.hl7.fhir.r4.model.IdType; 037import org.hl7.fhir.r5.elementmodel.Element; 038import org.hl7.fhir.r5.elementmodel.JsonParser; 039import org.hl7.fhir.r5.model.CanonicalResource; 040import org.hl7.fhir.r5.utils.validation.IResourceValidator; 041import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher; 042import org.hl7.fhir.utilities.CanonicalPair; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045 046import java.util.List; 047import java.util.Locale; 048 049public class ValidatorResourceFetcher implements IValidatorResourceFetcher { 050 051 private static final Logger ourLog = LoggerFactory.getLogger(ValidatorResourceFetcher.class); 052 053 private final FhirContext myFhirContext; 054 private final DaoRegistry myDaoRegistry; 055 private final VersionSpecificWorkerContextWrapper myVersionSpecificContextWrapper; 056 057 public ValidatorResourceFetcher( 058 FhirContext theFhirContext, IValidationSupport theValidationSupport, DaoRegistry theDaoRegistry) { 059 myFhirContext = theFhirContext; 060 myDaoRegistry = theDaoRegistry; 061 myVersionSpecificContextWrapper = 062 VersionSpecificWorkerContextWrapper.newVersionSpecificWorkerContextWrapper(theValidationSupport); 063 } 064 065 @Override 066 public Element fetch(IResourceValidator iResourceValidator, Object appContext, String theUrl) throws FHIRException { 067 IdType id = new IdType(theUrl); 068 String resourceType = id.getResourceType(); 069 IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(resourceType); 070 IBaseResource target; 071 try { 072 target = dao.read(id, (RequestDetails) appContext); 073 } catch (ResourceNotFoundException e) { 074 ourLog.info("Failed to resolve local reference: {}", theUrl); 075 try { 076 target = fetchByUrl(theUrl, dao, (RequestDetails) appContext); 077 } catch (ResourceNotFoundException e2) { 078 ourLog.info("Failed to find resource by URL: {}", theUrl); 079 return null; 080 } 081 } 082 try { 083 return new JsonParser(myVersionSpecificContextWrapper) 084 .parse(myFhirContext.newJsonParser().encodeResourceToString(target), resourceType); 085 } catch (Exception e) { 086 throw new FHIRException(Msg.code(576) + e); 087 } 088 } 089 090 private IBaseResource fetchByUrl(String url, IFhirResourceDao<?> dao, RequestDetails requestDetails) 091 throws ResourceNotFoundException { 092 CanonicalPair pair = new CanonicalPair(url); 093 SearchParameterMap searchParameterMap = new SearchParameterMap(); 094 searchParameterMap.add("url", new UriParam(pair.getUrl())); 095 String version = pair.getVersion(); 096 if (version != null && !version.isEmpty()) { 097 searchParameterMap.add("version", new TokenParam(version)); 098 } 099 List<IBaseResource> results = null; 100 try { 101 results = dao.search(searchParameterMap, requestDetails).getAllResources(); 102 } catch (InvalidRequestException e) { 103 ourLog.info("Resource does not support 'url' or 'version' Search Parameters"); 104 } 105 if (results != null && results.size() > 0) { 106 if (results.size() > 1) { 107 ourLog.warn( 108 String.format("Multiple results found for URL '%s', only the first will be considered.", url)); 109 } 110 return results.get(0); 111 } else { 112 throw new ResourceNotFoundException(Msg.code(2444) + "Failed to find resource by URL: " + url); 113 } 114 } 115 116 @Override 117 public boolean resolveURL( 118 IResourceValidator iResourceValidator, Object o, String s, String s1, String s2, boolean isCanonical) { 119 return true; 120 } 121 122 @Override 123 public byte[] fetchRaw(IResourceValidator iResourceValidator, String s) throws UnsupportedOperationException { 124 throw new UnsupportedOperationException(Msg.code(577)); 125 } 126 127 @Override 128 public IValidatorResourceFetcher setLocale(Locale locale) { 129 // ignore 130 return this; 131 } 132 133 @Override 134 public CanonicalResource fetchCanonicalResource(IResourceValidator iResourceValidator, String s) { 135 return null; 136 } 137 138 @Override 139 public boolean fetchesCanonicalResource(IResourceValidator iResourceValidator, String s) { 140 return false; 141 } 142}