001/* 002 * #%L 003 * HAPI FHIR JPA Server 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.provider; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.context.RuntimeResourceDefinition; 024import ca.uhn.fhir.context.RuntimeSearchParam; 025import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; 026import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao; 027import ca.uhn.fhir.jpa.util.ResourceCountCache; 028import ca.uhn.fhir.model.dstu2.composite.MetaDt; 029import ca.uhn.fhir.model.dstu2.resource.Bundle; 030import ca.uhn.fhir.model.dstu2.resource.Conformance; 031import ca.uhn.fhir.model.dstu2.resource.Conformance.Rest; 032import ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource; 033import ca.uhn.fhir.model.dstu2.resource.Conformance.RestResourceSearchParam; 034import ca.uhn.fhir.model.dstu2.valueset.ConditionalDeleteStatusEnum; 035import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum; 036import ca.uhn.fhir.model.dstu2.valueset.SearchParamTypeEnum; 037import ca.uhn.fhir.model.primitive.BoundCodeDt; 038import ca.uhn.fhir.model.primitive.DecimalDt; 039import ca.uhn.fhir.rest.api.server.RequestDetails; 040import ca.uhn.fhir.rest.server.RestfulServer; 041import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider; 042import ca.uhn.fhir.util.CoverageIgnore; 043import ca.uhn.fhir.util.ExtensionConstants; 044import jakarta.servlet.http.HttpServletRequest; 045 046import java.util.Collections; 047import java.util.List; 048import java.util.Map; 049 050import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 051import static org.apache.commons.lang3.StringUtils.isNotBlank; 052 053public class JpaConformanceProviderDstu2 extends ServerConformanceProvider { 054 055 private volatile Conformance myCachedValue; 056 private JpaStorageSettings myStorageSettings; 057 private String myImplementationDescription; 058 private boolean myIncludeResourceCounts; 059 private RestfulServer myRestfulServer; 060 private IFhirSystemDao<Bundle, MetaDt> mySystemDao; 061 private ResourceCountCache myResourceCountsCache; 062 063 /** 064 * Constructor 065 */ 066 @CoverageIgnore 067 public JpaConformanceProviderDstu2() { 068 super(); 069 super.setCache(false); 070 setIncludeResourceCounts(true); 071 } 072 073 /** 074 * Constructor 075 */ 076 public JpaConformanceProviderDstu2( 077 RestfulServer theRestfulServer, 078 IFhirSystemDao<Bundle, MetaDt> theSystemDao, 079 JpaStorageSettings theStorageSettings) { 080 super(theRestfulServer); 081 myRestfulServer = theRestfulServer; 082 mySystemDao = theSystemDao; 083 myStorageSettings = theStorageSettings; 084 super.setCache(false); 085 setIncludeResourceCounts(true); 086 } 087 088 @Override 089 public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { 090 Conformance retVal = myCachedValue; 091 092 Map<String, Long> counts = null; 093 if (myIncludeResourceCounts) { 094 counts = mySystemDao.getResourceCountsFromCache(); 095 } 096 counts = defaultIfNull(counts, Collections.emptyMap()); 097 098 FhirContext ctx = myRestfulServer.getFhirContext(); 099 100 retVal = super.getServerConformance(theRequest, theRequestDetails); 101 for (Rest nextRest : retVal.getRest()) { 102 103 for (RestResource nextResource : nextRest.getResource()) { 104 105 ConditionalDeleteStatusEnum conditionalDelete = 106 nextResource.getConditionalDeleteElement().getValueAsEnum(); 107 if (conditionalDelete == ConditionalDeleteStatusEnum.MULTIPLE_DELETES_SUPPORTED 108 && myStorageSettings.isAllowMultipleDelete() == false) { 109 nextResource.setConditionalDelete(ConditionalDeleteStatusEnum.SINGLE_DELETES_SUPPORTED); 110 } 111 112 // Add resource counts 113 Long count = counts.get(nextResource.getTypeElement().getValueAsString()); 114 if (count != null) { 115 nextResource.addUndeclaredExtension( 116 false, ExtensionConstants.CONF_RESOURCE_COUNT, new DecimalDt(count)); 117 } 118 119 // Add chained params 120 for (RestResourceSearchParam nextParam : nextResource.getSearchParam()) { 121 if (nextParam.getTypeElement().getValueAsEnum() == SearchParamTypeEnum.REFERENCE) { 122 List<BoundCodeDt<ResourceTypeEnum>> targets = nextParam.getTarget(); 123 for (BoundCodeDt<ResourceTypeEnum> next : targets) { 124 RuntimeResourceDefinition def = ctx.getResourceDefinition(next.getValue()); 125 for (RuntimeSearchParam nextChainedParam : def.getSearchParams()) { 126 nextParam.addChain(nextChainedParam.getName()); 127 } 128 } 129 } 130 } 131 } 132 } 133 134 if (isNotBlank(myImplementationDescription)) { 135 retVal.getImplementation().setDescription(myImplementationDescription); 136 } 137 myCachedValue = retVal; 138 return retVal; 139 } 140 141 public boolean isIncludeResourceCounts() { 142 return myIncludeResourceCounts; 143 } 144 145 public void setStorageSettings(JpaStorageSettings theStorageSettings) { 146 this.myStorageSettings = theStorageSettings; 147 } 148 149 @CoverageIgnore 150 public void setImplementationDescription(String theImplDesc) { 151 myImplementationDescription = theImplDesc; 152 } 153 154 public void setIncludeResourceCounts(boolean theIncludeResourceCounts) { 155 myIncludeResourceCounts = theIncludeResourceCounts; 156 } 157 158 @Override 159 public void setRestfulServer(RestfulServer theRestfulServer) { 160 this.myRestfulServer = theRestfulServer; 161 super.setRestfulServer(theRestfulServer); 162 } 163 164 @CoverageIgnore 165 public void setSystemDao(IFhirSystemDao<Bundle, MetaDt> mySystemDao) { 166 this.mySystemDao = mySystemDao; 167 } 168}