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}