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