001package ca.uhn.fhir.rest.method; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 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 static org.apache.commons.lang3.StringUtils.isBlank; 024 025import java.lang.reflect.Method; 026import java.util.HashSet; 027import java.util.Set; 028 029import javax.servlet.http.HttpServletResponse; 030 031import org.hl7.fhir.instance.model.api.IBase; 032import org.hl7.fhir.instance.model.api.IBaseResource; 033 034import ca.uhn.fhir.context.FhirContext; 035import ca.uhn.fhir.model.api.Bundle; 036import ca.uhn.fhir.model.api.Include; 037import ca.uhn.fhir.model.valueset.BundleTypeEnum; 038import ca.uhn.fhir.rest.api.RequestTypeEnum; 039import ca.uhn.fhir.rest.api.RestOperationTypeEnum; 040import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; 041import ca.uhn.fhir.rest.server.Constants; 042import ca.uhn.fhir.rest.server.EncodingEnum; 043import ca.uhn.fhir.rest.server.IBundleProvider; 044import ca.uhn.fhir.rest.server.IPagingProvider; 045import ca.uhn.fhir.rest.server.IRestfulServer; 046import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory; 047import ca.uhn.fhir.rest.server.RestfulServerUtils; 048import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 049import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 050import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; 051import ca.uhn.fhir.util.CoverageIgnore; 052 053public class PageMethodBinding extends BaseResourceReturningMethodBinding { 054 055 public PageMethodBinding(FhirContext theContext, Method theMethod) { 056 super(null, theMethod, theContext, null); 057 } 058 059 private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PageMethodBinding.class); 060 061 public IBaseResource provider() { 062 return null; 063 } 064 065 @Override 066 protected BundleTypeEnum getResponseBundleType() { 067 return null; 068 } 069 070 @Override 071 public ReturnTypeEnum getReturnType() { 072 return ReturnTypeEnum.BUNDLE; 073 } 074 075 @Override 076 public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException { 077 return handlePagingRequest(theServer, theRequest, null, theRequest.getParameters().get(Constants.PARAM_PAGINGACTION)[0]); 078 } 079 080 @Override 081 public ResourceOrDstu1Bundle invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, byte[] requestContents) { 082 IBase bundle = handlePagingRequest(theServer, theRequest, null, theRequest.getParameters().get(Constants.PARAM_PAGINGACTION)[0]); 083 if (bundle instanceof Bundle) { 084 return new ResourceOrDstu1Bundle((Bundle) bundle); 085 } else { 086 return new ResourceOrDstu1Bundle((IBaseResource) bundle); 087 } 088 } 089 090 private IBase handlePagingRequest(IRestfulServer<?> theServer, RequestDetails theRequest, HttpServletResponse theResponse, String thePagingAction) { 091 IPagingProvider pagingProvider = theServer.getPagingProvider(); 092 if (pagingProvider == null) { 093 throw new InvalidRequestException("This server does not support paging"); 094 } 095 IBundleProvider resultList = pagingProvider.retrieveResultList(thePagingAction); 096 if (resultList == null) { 097 ourLog.info("Client requested unknown paging ID[{}]", thePagingAction); 098 throw new ResourceGoneException("Search ID[" + thePagingAction + "] does not exist and may have expired."); 099 } 100 101 Integer count = RestfulServerUtils.extractCountParameter(theRequest); 102 if (count == null) { 103 count = pagingProvider.getDefaultPageSize(); 104 } else if (count > pagingProvider.getMaximumPageSize()) { 105 count = pagingProvider.getMaximumPageSize(); 106 } 107 108 Integer offsetI = RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_PAGINGOFFSET); 109 if (offsetI == null || offsetI < 0) { 110 offsetI = 0; 111 } 112 113 int start = Math.min(offsetI, resultList.size() - 1); 114 115 EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest, theServer.getDefaultResponseEncoding()); 116 boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest); 117 118 IVersionSpecificBundleFactory bundleFactory = theServer.getFhirContext().newBundleFactory(); 119 120 Set<Include> includes = new HashSet<Include>(); 121 String[] reqIncludes = theRequest.getParameters().get(Constants.PARAM_INCLUDE); 122 if (reqIncludes != null) { 123 for (String nextInclude : reqIncludes) { 124 includes.add(new Include(nextInclude)); 125 } 126 } 127 128 String linkSelfBase = theRequest.getFhirServerBase(); // myServerAddressStrategy.determineServerBase(getServletContext(), 129 // theRequest.getServletRequest()); 130 String completeUrl = theRequest.getCompleteUrl(); 131 String linkSelf = linkSelfBase + completeUrl.substring(theRequest.getCompleteUrl().indexOf('?')); 132 133 BundleTypeEnum bundleType = null; 134 String[] bundleTypeValues = theRequest.getParameters().get(Constants.PARAM_BUNDLETYPE); 135 if (bundleTypeValues != null) { 136 bundleType = BundleTypeEnum.VALUESET_BINDER.fromCodeString(bundleTypeValues[0]); 137 } 138 139 bundleFactory.initializeBundleFromBundleProvider(theServer, resultList, responseEncoding, theRequest.getFhirServerBase(), linkSelf, prettyPrint, start, count, thePagingAction, bundleType, includes); 140 141 Bundle bundle = bundleFactory.getDstu1Bundle(); 142 if (bundle != null) { 143 return bundle; 144 } else { 145 return bundleFactory.getResourceBundle(); 146 } 147 // if (bundle != null) { 148 // for (int i = getInterceptors().size() - 1; i >= 0; i--) { 149 // IServerInterceptor next = getInterceptors().get(i); 150 // boolean continueProcessing = next.outgoingResponse(theRequest, bundle, theRequest.getServletRequest(), 151 // theRequest.getServletResponse()); 152 // if (!continueProcessing) { 153 // ourLog.debug("Interceptor {} returned false, not continuing processing"); 154 // return; 155 // } 156 // } 157 // theRequest.getResponse().streamResponseAsBundle(bundle, summaryMode, respondGzip, requestIsBrowser); 158 // } else { 159 // IBaseResource resBundle = bundleFactory.getResourceBundle(); 160 // for (int i = getInterceptors().size() - 1; i >= 0; i--) { 161 // IServerInterceptor next = getInterceptors().get(i); 162 // boolean continueProcessing = next.outgoingResponse(theRequest, resBundle, theRequest.getServletRequest(), 163 // theRequest.getServletResponse()); 164 // if (!continueProcessing) { 165 // ourLog.debug("Interceptor {} returned false, not continuing processing"); 166 // return; 167 // } 168 // } 169 // theRequest.getResponse().streamResponseAsResource(resBundle, prettyPrint, summaryMode, 170 // Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), false); 171 // } 172 } 173 174 @Override 175 public RestOperationTypeEnum getRestOperationType() { 176 return RestOperationTypeEnum.GET_PAGE; 177 } 178 179 @Override 180 public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) { 181 String[] pageId = theRequest.getParameters().get(Constants.PARAM_PAGINGACTION); 182 if (pageId == null || pageId.length == 0 || isBlank(pageId[0])) { 183 return false; 184 } 185 if (theRequest.getRequestType() != RequestTypeEnum.GET) { 186 return false; 187 } 188 return true; 189 } 190 191 @CoverageIgnore 192 @Override 193 public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { 194 throw new UnsupportedOperationException(); 195 } 196 197}