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