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}