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