001package ca.uhn.fhir.jaxrs.server; 002 003/* 004 * #%L 005 * HAPI FHIR JAX-RS 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 java.io.IOException; 024import java.util.Collections; 025import java.util.List; 026 027import javax.interceptor.Interceptors; 028import javax.ws.rs.*; 029 030import javax.ws.rs.Produces; 031import javax.ws.rs.core.MediaType; 032import javax.ws.rs.core.Response; 033 034import ca.uhn.fhir.context.FhirContext; 035import ca.uhn.fhir.context.api.BundleInclusionRule; 036import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor; 037import ca.uhn.fhir.jaxrs.server.util.JaxRsMethodBindings; 038import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest; 039import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder; 040import ca.uhn.fhir.rest.api.*; 041import ca.uhn.fhir.rest.api.server.IBundleProvider; 042import ca.uhn.fhir.rest.api.server.IRestfulServer; 043import ca.uhn.fhir.rest.server.IPagingProvider; 044import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; 045import ca.uhn.fhir.rest.server.method.BaseMethodBinding; 046 047/** 048 * This server is the abstract superclass for all bundle providers. It exposes 049 * a large amount of the fhir api functionality using JAXRS 050 * 051 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare 052 */ 053@SuppressWarnings("javadoc") 054@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN }) 055@Consumes({ MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) 056@Interceptors(JaxRsExceptionInterceptor.class) 057public abstract class AbstractJaxRsBundleProvider extends AbstractJaxRsProvider implements IRestfulServer<JaxRsRequest>, IBundleProvider { 058 059 /** the method bindings for this class */ 060 private final JaxRsMethodBindings theBindings; 061 062 /** 063 * The default constructor. The method bindings are retrieved from the class 064 * being constructed. 065 */ 066 protected AbstractJaxRsBundleProvider() { 067 super(); 068 theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass()); 069 } 070 071 /** 072 * Provides the ability to specify the {@link FhirContext}. 073 * @param ctx the {@link FhirContext} instance. 074 */ 075 protected AbstractJaxRsBundleProvider(final FhirContext ctx) { 076 super(ctx); 077 theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass()); 078 } 079 080 /** 081 * This constructor takes in an explicit interface class. This subclass 082 * should be identical to the class being constructed but is given 083 * explicitly in order to avoid issues with proxy classes in a jee 084 * environment. 085 * 086 * @param theProviderClass the interface of the class 087 */ 088 protected AbstractJaxRsBundleProvider(final Class<? extends AbstractJaxRsProvider> theProviderClass) { 089 theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass); 090 } 091 092 /** 093 * Create all resources in one transaction 094 * 095 * @param resource the body of the post method containing the bundle of the resources being created in a xml/json form 096 * @return the response 097 * @see <a href="https://www.hl7.org/fhir/http.html#create">https://www.hl7. org/fhir/http.html#create</a> 098 */ 099 @POST 100 public Response create(final String resource) 101 throws IOException { 102 return execute(getRequest(RequestTypeEnum.POST, RestOperationTypeEnum.TRANSACTION).resource(resource)); 103 } 104 105 /** 106 * Search the resource type based on some filter criteria 107 * 108 * @return the response 109 * @see <a href="https://www.hl7.org/fhir/http.html#search">https://www.hl7.org/fhir/http.html#search</a> 110 */ 111 @GET 112 public Response search() 113 throws IOException { 114 return execute(getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE)); 115 } 116 117 /** 118 * Execute the method described by the requestBuilder and methodKey 119 * 120 * @param theRequestBuilder the requestBuilder that contains the information about the request 121 * @param methodKey the key determining the method to be executed 122 * @return the response 123 */ 124 private Response execute(final Builder theRequestBuilder, final String methodKey) 125 throws IOException { 126 final JaxRsRequest theRequest = theRequestBuilder.build(); 127 final BaseMethodBinding<?> method = getBinding(theRequest.getRestOperationType(), methodKey); 128 try { 129 return (Response) method.invokeServer(this, theRequest); 130 } 131 catch (final Throwable theException) { 132 return handleException(theRequest, theException); 133 } 134 } 135 136 /** 137 * Execute the method described by the requestBuilder 138 * 139 * @param theRequestBuilder the requestBuilder that contains the information about the request 140 * @return the response 141 */ 142 private Response execute(final Builder theRequestBuilder) 143 throws IOException { 144 return execute(theRequestBuilder, JaxRsMethodBindings.DEFAULT_METHOD_KEY); 145 } 146 147 /** 148 * Return the method binding for the given rest operation 149 * 150 * @param restOperation the rest operation to retrieve 151 * @param theBindingKey the key determining the method to be executed (needed for e.g. custom operation) 152 * @return 153 */ 154 protected BaseMethodBinding<?> getBinding(final RestOperationTypeEnum restOperation, final String theBindingKey) { 155 return getBindings().getBinding(restOperation, theBindingKey); 156 } 157 158 /** 159 * Default: an empty list of interceptors 160 * 161 * @see ca.uhn.fhir.rest.server.IRestfulServerDefaults#getInterceptors_() 162 */ 163 @Override 164 public List<IServerInterceptor> getInterceptors_() { 165 return Collections.emptyList(); 166 } 167 168 /** 169 * Default: no paging provider 170 */ 171 @Override 172 public IPagingProvider getPagingProvider() { 173 return null; 174 } 175 176 /** 177 * Default: BundleInclusionRule.BASED_ON_INCLUDES 178 */ 179 @Override 180 public BundleInclusionRule getBundleInclusionRule() { 181 return BundleInclusionRule.BASED_ON_INCLUDES; 182 } 183 184 /** 185 * Return the bindings defined in this resource provider 186 * 187 * @return the jax-rs method bindings 188 */ 189 public JaxRsMethodBindings getBindings() { 190 return theBindings; 191 } 192 193}