001package ca.uhn.fhir.jaxrs.server;
002
003import java.io.IOException;
004/*
005 * #%L
006 * HAPI FHIR JAX-RS Server
007 * %%
008 * Copyright (C) 2014 - 2019 University Health Network
009 * %%
010 * Licensed under the Apache License, Version 2.0 (the "License");
011 * you may not use this file except in compliance with the License.
012 * You may obtain a copy of the License at
013 * 
014 * http://www.apache.org/licenses/LICENSE-2.0
015 * 
016 * Unless required by applicable law or agreed to in writing, software
017 * distributed under the License is distributed on an "AS IS" BASIS,
018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019 * See the License for the specific language governing permissions and
020 * limitations under the License.
021 * #L%
022 */
023import java.util.*;
024import java.util.Map.Entry;
025
026import javax.ws.rs.core.*;
027
028import ca.uhn.fhir.interceptor.api.IInterceptorService;
029import org.apache.commons.lang3.StringUtils;
030
031import ca.uhn.fhir.context.FhirContext;
032import ca.uhn.fhir.context.api.AddProfileTagEnum;
033import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
034import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException;
035import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
036import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
037import ca.uhn.fhir.rest.api.*;
038import ca.uhn.fhir.rest.server.*;
039import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
040
041/**
042 * This is the abstract superclass for all jaxrs providers. It contains some defaults implementing
043 * the IRestfulServerDefaults interface and exposes the uri and headers.
044 *
045 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
046 */
047public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
048
049        private static final String ERROR = "error";
050
051        private static final String PROCESSING = "processing";
052
053        private final FhirContext CTX;
054        /** the http headers */
055        @Context
056        private HttpHeaders myHeaders;
057
058        /** the uri info */
059        @Context
060        private UriInfo myUriInfo;
061
062        /**
063         * Default is DSTU2. Use {@link AbstractJaxRsProvider#AbstractJaxRsProvider(FhirContext)} to specify a DSTU3 context.
064         */
065        protected AbstractJaxRsProvider() {
066                CTX = FhirContext.forDstu2();
067        }
068
069        /**
070         *
071         * @param ctx
072         *           the {@link FhirContext} to support.
073         */
074        protected AbstractJaxRsProvider(final FhirContext ctx) {
075                CTX = ctx;
076        }
077
078        @Override
079        public IInterceptorService getInterceptorService() {
080                return null;
081        }
082
083        /**
084         * DEFAULT = AddProfileTagEnum.NEVER
085         */
086        @Override
087        public AddProfileTagEnum getAddProfileTag() {
088                return AddProfileTagEnum.NEVER;
089        }
090
091        /**
092         * This method returns the server base, including the resource path.
093         * {@link UriInfo#getBaseUri() UriInfo#getBaseUri()}
094         * 
095         * @return the ascii string for the base resource provider path
096         */
097        public String getBaseForRequest() {
098                return getBaseForServer();
099        }
100
101        /**
102         * This method returns the server base, independent of the request or resource.
103         * 
104         * @see javax.ws.rs.core.UriInfo#getBaseUri()
105         * @return the ascii string for the server base
106         */
107        public String getBaseForServer() {
108                final String url = getUriInfo().getBaseUri().toASCIIString();
109                return StringUtils.isNotBlank(url) && url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
110        }
111
112        /**
113         * DEFAULT = EncodingEnum.JSON
114         */
115        @Override
116        public EncodingEnum getDefaultResponseEncoding() {
117                return EncodingEnum.JSON;
118        }
119
120        /**
121         * DEFAULT = ETagSupportEnum.DISABLED
122         */
123        @Override
124        public ETagSupportEnum getETagSupport() {
125                return ETagSupportEnum.DISABLED;
126        }
127
128        /**
129         * DEFAULT = {@link ElementsSupportEnum#STANDARD}
130         */
131        @Override
132        public ElementsSupportEnum getElementsSupport() {
133                return ElementsSupportEnum.STANDARD;
134        }
135
136        @Override
137        public FhirContext getFhirContext() {
138                return CTX;
139        }
140
141        /**
142         * Get the headers
143         * 
144         * @return the headers
145         */
146        public HttpHeaders getHeaders() {
147                return this.myHeaders;
148        }
149
150        /**
151         * Default: an empty list of interceptors (Interceptors are not yet supported
152         * in the JAX-RS server). Please get in touch if you'd like to help!
153         * 
154         * @see ca.uhn.fhir.rest.server.IRestfulServerDefaults#getInterceptors_()
155         */
156        @Override
157        public List<IServerInterceptor> getInterceptors_() {
158                return Collections.emptyList();
159        }
160
161        /**
162         * By default, no paging provider is used
163         */
164        @Override
165        public IPagingProvider getPagingProvider() {
166                return null;
167        }
168
169        /**
170         * This method returns the query parameters
171         * 
172         * @return the query parameters
173         */
174        public Map<String, String[]> getParameters() {
175                final MultivaluedMap<String, String> queryParameters = getUriInfo().getQueryParameters();
176                final HashMap<String, String[]> params = new HashMap<String, String[]>();
177                for (final Entry<String, List<String>> paramEntry : queryParameters.entrySet()) {
178                        params.put(paramEntry.getKey(), paramEntry.getValue().toArray(new String[paramEntry.getValue().size()]));
179                }
180                return params;
181        }
182
183        /**
184         * Return the requestbuilder for the server
185         * 
186         * @param requestType
187         *           the type of the request
188         * @param restOperation
189         *           the rest operation type
190         * @return the requestbuilder
191         */
192        public Builder getRequest(final RequestTypeEnum requestType, final RestOperationTypeEnum restOperation) {
193                return getRequest(requestType, restOperation, null);
194        }
195
196        /**
197         * Return the requestbuilder for the server
198         * 
199         * @param requestType
200         *           the type of the request
201         * @param restOperation
202         *           the rest operation type
203         * @param theResourceName
204         *           the resource name
205         * @return the requestbuilder
206         */
207        public Builder getRequest(final RequestTypeEnum requestType, final RestOperationTypeEnum restOperation, final String theResourceName) {
208                return new JaxRsRequest.Builder(this, requestType, restOperation, myUriInfo.getRequestUri().toString(), theResourceName);
209        }
210
211        /**
212         * This method returns the default server address strategy. The default strategy return the
213         * base uri for the request {@link AbstractJaxRsProvider#getBaseForRequest() getBaseForRequest()}
214         * 
215         * @return
216         */
217        public IServerAddressStrategy getServerAddressStrategy() {
218                final HardcodedServerAddressStrategy addressStrategy = new HardcodedServerAddressStrategy();
219                addressStrategy.setValue(getBaseForRequest());
220                return addressStrategy;
221        }
222
223        /**
224         * Get the uriInfo
225         * 
226         * @return the uri info
227         */
228        public UriInfo getUriInfo() {
229                return this.myUriInfo;
230        }
231
232        /**
233         * Convert an exception to a response
234         * 
235         * @param theRequest
236         *           the incoming request
237         * @param theException
238         *           the exception to convert
239         * @return response
240         * @throws IOException
241         */
242        public Response handleException(final JaxRsRequest theRequest, final Throwable theException)
243                        throws IOException {
244                if (theException instanceof JaxRsResponseException) {
245                        return new JaxRsExceptionInterceptor().convertExceptionIntoResponse(theRequest, (JaxRsResponseException) theException);
246                } else {
247                        return new JaxRsExceptionInterceptor().convertExceptionIntoResponse(theRequest,
248                                        new JaxRsExceptionInterceptor().convertException(this, theException));
249                }
250        }
251
252        /**
253         * DEFAULT = true
254         */
255        @Override
256        public boolean isDefaultPrettyPrint() {
257                return true;
258        }
259
260        /**
261         * Set the headers
262         * 
263         * @param headers
264         *           the headers to set
265         */
266        public void setHeaders(final HttpHeaders headers) {
267                this.myHeaders = headers;
268        }
269
270        /**
271         * Set the Uri Info
272         * 
273         * @param uriInfo
274         *           the uri info
275         */
276        public void setUriInfo(final UriInfo uriInfo) {
277                this.myUriInfo = uriInfo;
278        }
279
280        /**
281         * DEFAULT = false
282         */
283        public boolean withStackTrace() {
284                return false;
285        }
286}