
001package ca.uhn.fhir.jpa.provider.dstu3; 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.RuntimeSearchParam; 024import ca.uhn.fhir.jpa.api.config.DaoConfig; 025import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao; 026import ca.uhn.fhir.rest.api.Constants; 027import ca.uhn.fhir.rest.api.server.RequestDetails; 028import ca.uhn.fhir.rest.server.RestfulServer; 029import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; 030import ca.uhn.fhir.rest.server.util.ResourceSearchParams; 031import ca.uhn.fhir.util.CoverageIgnore; 032import ca.uhn.fhir.util.ExtensionConstants; 033import org.hl7.fhir.dstu3.model.Bundle; 034import org.hl7.fhir.dstu3.model.CapabilityStatement; 035import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent; 036import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent; 037import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent; 038import org.hl7.fhir.dstu3.model.CapabilityStatement.ConditionalDeleteStatus; 039import org.hl7.fhir.dstu3.model.CapabilityStatement.ResourceVersionPolicy; 040import org.hl7.fhir.dstu3.model.DecimalType; 041import org.hl7.fhir.dstu3.model.Enumerations.SearchParamType; 042import org.hl7.fhir.dstu3.model.Extension; 043import org.hl7.fhir.dstu3.model.Meta; 044import org.hl7.fhir.dstu3.model.UriType; 045 046import javax.servlet.http.HttpServletRequest; 047import java.util.Collections; 048import java.util.Map; 049 050import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 051import static org.apache.commons.lang3.StringUtils.isNotBlank; 052 053public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider { 054 055 private volatile CapabilityStatement myCachedValue; 056 private DaoConfig myDaoConfig; 057 private ISearchParamRegistry mySearchParamRegistry; 058 private String myImplementationDescription; 059 private boolean myIncludeResourceCounts; 060 private RestfulServer myRestfulServer; 061 private IFhirSystemDao<Bundle, Meta> mySystemDao; 062 063 /** 064 * Constructor 065 */ 066 @CoverageIgnore 067 public JpaConformanceProviderDstu3() { 068 super(); 069 super.setCache(false); 070 setIncludeResourceCounts(true); 071 } 072 073 /** 074 * Constructor 075 */ 076 public JpaConformanceProviderDstu3(RestfulServer theRestfulServer, IFhirSystemDao<Bundle, Meta> theSystemDao, DaoConfig theDaoConfig, ISearchParamRegistry theSearchParamRegistry) { 077 super(theRestfulServer); 078 myRestfulServer = theRestfulServer; 079 mySystemDao = theSystemDao; 080 myDaoConfig = theDaoConfig; 081 super.setCache(false); 082 setSearchParamRegistry(theSearchParamRegistry); 083 setIncludeResourceCounts(true); 084 } 085 086 public void setSearchParamRegistry(ISearchParamRegistry theSearchParamRegistry) { 087 mySearchParamRegistry = theSearchParamRegistry; 088 } 089 090 @Override 091 public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { 092 CapabilityStatement 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 retVal = super.getServerConformance(theRequest, theRequestDetails); 101 for (CapabilityStatementRestComponent nextRest : retVal.getRest()) { 102 103 for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) { 104 105 nextResource.setVersioning(ResourceVersionPolicy.VERSIONEDUPDATE); 106 107 ConditionalDeleteStatus conditionalDelete = nextResource.getConditionalDelete(); 108 if (conditionalDelete == ConditionalDeleteStatus.MULTIPLE && myDaoConfig.isAllowMultipleDelete() == false) { 109 nextResource.setConditionalDelete(ConditionalDeleteStatus.SINGLE); 110 } 111 112 // Add resource counts 113 Long count = counts.get(nextResource.getTypeElement().getValueAsString()); 114 if (count != null) { 115 nextResource.addExtension(new Extension(ExtensionConstants.CONF_RESOURCE_COUNT, new DecimalType(count))); 116 } 117 118 nextResource.getSearchParam().clear(); 119 String resourceName = nextResource.getType(); 120 ResourceSearchParams searchParams = mySearchParamRegistry.getActiveSearchParams(resourceName); 121 for (RuntimeSearchParam runtimeSp : searchParams.values()) { 122 CapabilityStatementRestResourceSearchParamComponent confSp = nextResource.addSearchParam(); 123 124 confSp.setName(runtimeSp.getName()); 125 confSp.setDocumentation(runtimeSp.getDescription()); 126 confSp.setDefinition(runtimeSp.getUri()); 127 switch (runtimeSp.getParamType()) { 128 case COMPOSITE: 129 confSp.setType(SearchParamType.COMPOSITE); 130 break; 131 case DATE: 132 confSp.setType(SearchParamType.DATE); 133 break; 134 case NUMBER: 135 confSp.setType(SearchParamType.NUMBER); 136 break; 137 case QUANTITY: 138 confSp.setType(SearchParamType.QUANTITY); 139 break; 140 case REFERENCE: 141 confSp.setType(SearchParamType.REFERENCE); 142 break; 143 case STRING: 144 confSp.setType(SearchParamType.STRING); 145 break; 146 case TOKEN: 147 confSp.setType(SearchParamType.TOKEN); 148 break; 149 case URI: 150 confSp.setType(SearchParamType.URI); 151 break; 152 case HAS: 153 // Shouldn't happen 154 break; 155 } 156 157 } 158 159 } 160 } 161 162 massage(retVal); 163 164 if (myDaoConfig.getSupportedSubscriptionTypes().contains(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.WEBSOCKET)) { 165 if (isNotBlank(myDaoConfig.getWebsocketContextPath())) { 166 Extension websocketExtension = new Extension(); 167 websocketExtension.setUrl(Constants.CAPABILITYSTATEMENT_WEBSOCKET_URL); 168 websocketExtension.setValue(new UriType(myDaoConfig.getWebsocketContextPath())); 169 retVal.getRestFirstRep().addExtension(websocketExtension); 170 } 171 } 172 173 retVal.getImplementation().setDescription(myImplementationDescription); 174 myCachedValue = retVal; 175 return retVal; 176 } 177 178 public boolean isIncludeResourceCounts() { 179 return myIncludeResourceCounts; 180 } 181 182 public void setIncludeResourceCounts(boolean theIncludeResourceCounts) { 183 myIncludeResourceCounts = theIncludeResourceCounts; 184 } 185 186 /** 187 * Subclasses may override 188 */ 189 protected void massage(CapabilityStatement theStatement) { 190 // nothing 191 } 192 193 public void setDaoConfig(DaoConfig myDaoConfig) { 194 this.myDaoConfig = myDaoConfig; 195 } 196 197 @CoverageIgnore 198 public void setImplementationDescription(String theImplDesc) { 199 myImplementationDescription = theImplDesc; 200 } 201 202 @Override 203 public void setRestfulServer(RestfulServer theRestfulServer) { 204 this.myRestfulServer = theRestfulServer; 205 super.setRestfulServer(theRestfulServer); 206 } 207 208 @CoverageIgnore 209 public void setSystemDao(IFhirSystemDao<Bundle, Meta> mySystemDao) { 210 this.mySystemDao = mySystemDao; 211 } 212}