
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.support.IValidationSupport; 024import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; 025import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao; 026import ca.uhn.fhir.rest.api.Constants; 027import ca.uhn.fhir.rest.server.RestfulServer; 028import ca.uhn.fhir.rest.server.provider.ServerCapabilityStatementProvider; 029import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; 030import ca.uhn.fhir.util.CoverageIgnore; 031import ca.uhn.fhir.util.ExtensionConstants; 032import ca.uhn.fhir.util.ExtensionUtil; 033import ca.uhn.fhir.util.FhirTerser; 034import org.apache.commons.lang3.Validate; 035import org.hl7.fhir.instance.model.api.IBase; 036import org.hl7.fhir.instance.model.api.IBaseConformance; 037import org.hl7.fhir.r4.model.Bundle; 038import org.hl7.fhir.r4.model.CapabilityStatement.ConditionalDeleteStatus; 039import org.hl7.fhir.r4.model.CapabilityStatement.ResourceVersionPolicy; 040import org.hl7.fhir.r4.model.Meta; 041 042import javax.annotation.Nonnull; 043import java.util.Map; 044 045import static org.apache.commons.lang3.StringUtils.isNotBlank; 046 047/** 048 * R4+ Only 049 */ 050public class JpaCapabilityStatementProvider extends ServerCapabilityStatementProvider { 051 052 private final FhirContext myContext; 053 private JpaStorageSettings myStorageSettings; 054 private String myImplementationDescription; 055 private boolean myIncludeResourceCounts; 056 private IFhirSystemDao<?, ?> mySystemDao; 057 058 /** 059 * Constructor 060 */ 061 public JpaCapabilityStatementProvider(@Nonnull RestfulServer theRestfulServer, @Nonnull IFhirSystemDao<?, ?> theSystemDao, @Nonnull JpaStorageSettings theStorageSettings, @Nonnull ISearchParamRegistry theSearchParamRegistry, IValidationSupport theValidationSupport) { 062 super(theRestfulServer, theSearchParamRegistry, theValidationSupport); 063 064 Validate.notNull(theRestfulServer); 065 Validate.notNull(theSystemDao); 066 Validate.notNull(theStorageSettings); 067 Validate.notNull(theSearchParamRegistry); 068 069 myContext = theRestfulServer.getFhirContext(); 070 mySystemDao = theSystemDao; 071 myStorageSettings = theStorageSettings; 072 setIncludeResourceCounts(true); 073 } 074 075 @Override 076 protected void postProcess(FhirTerser theTerser, IBaseConformance theCapabilityStatement) { 077 super.postProcess(theTerser, theCapabilityStatement); 078 079 if (isNotBlank(myImplementationDescription)) { 080 theTerser.setElement(theCapabilityStatement, "implementation.description", myImplementationDescription); 081 } 082 083 theTerser.addElement(theCapabilityStatement, "patchFormat", Constants.CT_FHIR_JSON_NEW); 084 theTerser.addElement(theCapabilityStatement, "patchFormat", Constants.CT_FHIR_XML_NEW); 085 theTerser.addElement(theCapabilityStatement, "patchFormat", Constants.CT_JSON_PATCH); 086 theTerser.addElement(theCapabilityStatement, "patchFormat", Constants.CT_XML_PATCH); 087 } 088 089 @Override 090 protected void postProcessRest(FhirTerser theTerser, IBase theRest) { 091 super.postProcessRest(theTerser, theRest); 092 093 if (myStorageSettings.getSupportedSubscriptionTypes().contains(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.WEBSOCKET)) { 094 if (isNotBlank(myStorageSettings.getWebsocketContextPath())) { 095 ExtensionUtil.setExtension(myContext, theRest, Constants.CAPABILITYSTATEMENT_WEBSOCKET_URL, "uri", myStorageSettings.getWebsocketContextPath()); 096 } 097 } 098 099 } 100 101 @Override 102 protected void postProcessRestResource(FhirTerser theTerser, IBase theResource, String theResourceName) { 103 super.postProcessRestResource(theTerser, theResource, theResourceName); 104 105 theTerser.addElement(theResource, "versioning", ResourceVersionPolicy.VERSIONEDUPDATE.toCode()); 106 107 if (myStorageSettings.isAllowMultipleDelete()) { 108 theTerser.addElement(theResource, "conditionalDelete", ConditionalDeleteStatus.MULTIPLE.toCode()); 109 } else { 110 theTerser.addElement(theResource, "conditionalDelete", ConditionalDeleteStatus.SINGLE.toCode()); 111 } 112 113 // Add resource counts 114 if (myIncludeResourceCounts) { 115 Map<String, Long> counts = mySystemDao.getResourceCountsFromCache(); 116 if (counts != null) { 117 Long count = counts.get(theResourceName); 118 if (count != null) { 119 ExtensionUtil.setExtension(myContext, theResource, ExtensionConstants.CONF_RESOURCE_COUNT, "decimal", Long.toString(count)); 120 } 121 } 122 } 123 124 } 125 126 public boolean isIncludeResourceCounts() { 127 return myIncludeResourceCounts; 128 } 129 130 public void setIncludeResourceCounts(boolean theIncludeResourceCounts) { 131 myIncludeResourceCounts = theIncludeResourceCounts; 132 } 133 134 public void setStorageSettings(JpaStorageSettings theStorageSettings) { 135 this.myStorageSettings = theStorageSettings; 136 } 137 138 @CoverageIgnore 139 public void setImplementationDescription(String theImplDesc) { 140 myImplementationDescription = theImplDesc; 141 } 142 143 @CoverageIgnore 144 public void setSystemDao(IFhirSystemDao<Bundle, Meta> mySystemDao) { 145 this.mySystemDao = mySystemDao; 146 } 147 148 @Override 149 protected boolean searchParamEnabled(String theSearchParam) { 150 return !Constants.PARAM_FILTER.equals(theSearchParam) || myStorageSettings.isFilterParameterEnabled(); 151 } 152}