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