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