001package ca.uhn.fhir.jpa.provider.dstu3;
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.RuntimeSearchParam;
024import ca.uhn.fhir.jpa.api.config.DaoConfig;
025import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
026import ca.uhn.fhir.rest.api.Constants;
027import ca.uhn.fhir.rest.api.server.RequestDetails;
028import ca.uhn.fhir.rest.server.RestfulServer;
029import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
030import ca.uhn.fhir.rest.server.util.ResourceSearchParams;
031import ca.uhn.fhir.util.CoverageIgnore;
032import ca.uhn.fhir.util.ExtensionConstants;
033import org.hl7.fhir.dstu3.model.Bundle;
034import org.hl7.fhir.dstu3.model.CapabilityStatement;
035import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent;
036import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
037import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
038import org.hl7.fhir.dstu3.model.CapabilityStatement.ConditionalDeleteStatus;
039import org.hl7.fhir.dstu3.model.CapabilityStatement.ResourceVersionPolicy;
040import org.hl7.fhir.dstu3.model.DecimalType;
041import org.hl7.fhir.dstu3.model.Enumerations.SearchParamType;
042import org.hl7.fhir.dstu3.model.Extension;
043import org.hl7.fhir.dstu3.model.Meta;
044import org.hl7.fhir.dstu3.model.UriType;
045
046import javax.servlet.http.HttpServletRequest;
047import java.util.Collections;
048import java.util.Map;
049
050import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
051import static org.apache.commons.lang3.StringUtils.isNotBlank;
052
053public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider {
054
055        private volatile CapabilityStatement myCachedValue;
056        private DaoConfig myDaoConfig;
057        private ISearchParamRegistry mySearchParamRegistry;
058        private String myImplementationDescription;
059        private boolean myIncludeResourceCounts;
060        private RestfulServer myRestfulServer;
061        private IFhirSystemDao<Bundle, Meta> mySystemDao;
062
063        /**
064         * Constructor
065         */
066        @CoverageIgnore
067        public JpaConformanceProviderDstu3() {
068                super();
069                super.setCache(false);
070                setIncludeResourceCounts(true);
071        }
072
073        /**
074         * Constructor
075         */
076        public JpaConformanceProviderDstu3(RestfulServer theRestfulServer, IFhirSystemDao<Bundle, Meta> theSystemDao, DaoConfig theDaoConfig, ISearchParamRegistry theSearchParamRegistry) {
077                super(theRestfulServer);
078                myRestfulServer = theRestfulServer;
079                mySystemDao = theSystemDao;
080                myDaoConfig = theDaoConfig;
081                super.setCache(false);
082                setSearchParamRegistry(theSearchParamRegistry);
083                setIncludeResourceCounts(true);
084        }
085
086        public void setSearchParamRegistry(ISearchParamRegistry theSearchParamRegistry) {
087                mySearchParamRegistry = theSearchParamRegistry;
088        }
089
090        @Override
091        public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
092                CapabilityStatement 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                retVal = super.getServerConformance(theRequest, theRequestDetails);
101                for (CapabilityStatementRestComponent nextRest : retVal.getRest()) {
102
103                        for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) {
104
105                                nextResource.setVersioning(ResourceVersionPolicy.VERSIONEDUPDATE);
106
107                                ConditionalDeleteStatus conditionalDelete = nextResource.getConditionalDelete();
108                                if (conditionalDelete == ConditionalDeleteStatus.MULTIPLE && myDaoConfig.isAllowMultipleDelete() == false) {
109                                        nextResource.setConditionalDelete(ConditionalDeleteStatus.SINGLE);
110                                }
111
112                                // Add resource counts
113                                Long count = counts.get(nextResource.getTypeElement().getValueAsString());
114                                if (count != null) {
115                                        nextResource.addExtension(new Extension(ExtensionConstants.CONF_RESOURCE_COUNT, new DecimalType(count)));
116                                }
117
118                                nextResource.getSearchParam().clear();
119                                String resourceName = nextResource.getType();
120                                ResourceSearchParams searchParams = mySearchParamRegistry.getActiveSearchParams(resourceName);
121                                for (RuntimeSearchParam runtimeSp : searchParams.values()) {
122                                        CapabilityStatementRestResourceSearchParamComponent confSp = nextResource.addSearchParam();
123
124                                        confSp.setName(runtimeSp.getName());
125                                        confSp.setDocumentation(runtimeSp.getDescription());
126                                        confSp.setDefinition(runtimeSp.getUri());
127                                        switch (runtimeSp.getParamType()) {
128                                                case COMPOSITE:
129                                                        confSp.setType(SearchParamType.COMPOSITE);
130                                                        break;
131                                                case DATE:
132                                                        confSp.setType(SearchParamType.DATE);
133                                                        break;
134                                                case NUMBER:
135                                                        confSp.setType(SearchParamType.NUMBER);
136                                                        break;
137                                                case QUANTITY:
138                                                        confSp.setType(SearchParamType.QUANTITY);
139                                                        break;
140                                                case REFERENCE:
141                                                        confSp.setType(SearchParamType.REFERENCE);
142                                                        break;
143                                                case STRING:
144                                                        confSp.setType(SearchParamType.STRING);
145                                                        break;
146                                                case TOKEN:
147                                                        confSp.setType(SearchParamType.TOKEN);
148                                                        break;
149                                                case URI:
150                                                        confSp.setType(SearchParamType.URI);
151                                                        break;
152                                                case HAS:
153                                                        // Shouldn't happen
154                                                        break;
155                                        }
156
157                                }
158
159                        }
160                }
161
162                massage(retVal);
163
164                if (myDaoConfig.getSupportedSubscriptionTypes().contains(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.WEBSOCKET)) {
165                        if (isNotBlank(myDaoConfig.getWebsocketContextPath())) {
166                                Extension websocketExtension = new Extension();
167                                websocketExtension.setUrl(Constants.CAPABILITYSTATEMENT_WEBSOCKET_URL);
168                                websocketExtension.setValue(new UriType(myDaoConfig.getWebsocketContextPath()));
169                                retVal.getRestFirstRep().addExtension(websocketExtension);
170                        }
171                }
172
173                retVal.getImplementation().setDescription(myImplementationDescription);
174                myCachedValue = retVal;
175                return retVal;
176        }
177
178        public boolean isIncludeResourceCounts() {
179                return myIncludeResourceCounts;
180        }
181
182        public void setIncludeResourceCounts(boolean theIncludeResourceCounts) {
183                myIncludeResourceCounts = theIncludeResourceCounts;
184        }
185
186        /**
187         * Subclasses may override
188         */
189        protected void massage(CapabilityStatement theStatement) {
190                // nothing
191        }
192
193        public void setDaoConfig(DaoConfig myDaoConfig) {
194                this.myDaoConfig = myDaoConfig;
195        }
196
197        @CoverageIgnore
198        public void setImplementationDescription(String theImplDesc) {
199                myImplementationDescription = theImplDesc;
200        }
201
202        @Override
203        public void setRestfulServer(RestfulServer theRestfulServer) {
204                this.myRestfulServer = theRestfulServer;
205                super.setRestfulServer(theRestfulServer);
206        }
207
208        @CoverageIgnore
209        public void setSystemDao(IFhirSystemDao<Bundle, Meta> mySystemDao) {
210                this.mySystemDao = mySystemDao;
211        }
212}