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