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