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