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