001package ca.uhn.fhir.rest.client.method; 002 003/* 004 * #%L 005 * HAPI FHIR - Client Framework 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.io.InputStream; 025import java.lang.reflect.Method; 026import java.util.*; 027 028import org.apache.commons.io.IOUtils; 029import org.apache.commons.lang3.Validate; 030import org.hl7.fhir.instance.model.api.*; 031 032import ca.uhn.fhir.context.ConfigurationException; 033import ca.uhn.fhir.context.FhirContext; 034import ca.uhn.fhir.model.primitive.IdDt; 035import ca.uhn.fhir.model.valueset.BundleTypeEnum; 036import ca.uhn.fhir.rest.annotation.*; 037import ca.uhn.fhir.rest.api.RestOperationTypeEnum; 038import ca.uhn.fhir.rest.param.ParameterUtil; 039import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; 040 041public class ReadMethodBinding extends BaseResourceReturningMethodBinding implements IClientResponseHandlerHandlesBinary<Object> { 042 private Integer myIdIndex; 043 private boolean mySupportsVersion; 044 private Class<? extends IIdType> myIdParameterType; 045 046 @SuppressWarnings("unchecked") 047 public ReadMethodBinding(Class<? extends IBaseResource> theAnnotatedResourceType, Method theMethod, FhirContext theContext, Object theProvider) { 048 super(theAnnotatedResourceType, theMethod, theContext, theProvider); 049 050 Validate.notNull(theMethod, "Method must not be null"); 051 052 Integer idIndex = ParameterUtil.findIdParameterIndex(theMethod, getContext()); 053 054 Class<?>[] parameterTypes = theMethod.getParameterTypes(); 055 056 mySupportsVersion = theMethod.getAnnotation(Read.class).version(); 057 myIdIndex = idIndex; 058 059 if (myIdIndex == null) { 060 throw new ConfigurationException("@" + Read.class.getSimpleName() + " method " + theMethod.getName() + " on type \"" + theMethod.getDeclaringClass().getName() 061 + "\" does not have a parameter annotated with @" + IdParam.class.getSimpleName()); 062 } 063 myIdParameterType = (Class<? extends IIdType>) parameterTypes[myIdIndex]; 064 065 if (!IIdType.class.isAssignableFrom(myIdParameterType)) { 066 throw new ConfigurationException("ID parameter must be of type IdDt or IdType - Found: " + myIdParameterType); 067 } 068 069 } 070 071 @Override 072 public List<Class<?>> getAllowableParamAnnotations() { 073 ArrayList<Class<?>> retVal = new ArrayList<Class<?>>(); 074 retVal.add(IdParam.class); 075 retVal.add(Elements.class); 076 return retVal; 077 } 078 079 @Override 080 public RestOperationTypeEnum getRestOperationType() { 081 return isVread() ? RestOperationTypeEnum.VREAD : RestOperationTypeEnum.READ; 082 } 083 084 @Override 085 public ReturnTypeEnum getReturnType() { 086 return ReturnTypeEnum.RESOURCE; 087 } 088 089 @Override 090 public HttpGetClientInvocation invokeClient(Object[] theArgs) { 091 HttpGetClientInvocation retVal; 092 IIdType id = ((IIdType) theArgs[myIdIndex]); 093 String resourceName = getResourceName(); 094 if (id.hasVersionIdPart()) { 095 retVal = createVReadInvocation(getContext(), new IdDt(resourceName, id.getIdPart(), id.getVersionIdPart()), resourceName); 096 } else { 097 retVal = createReadInvocation(getContext(), id, resourceName); 098 } 099 100 for (int idx = 0; idx < theArgs.length; idx++) { 101 IParameter nextParam = getParameters().get(idx); 102 nextParam.translateClientArgumentIntoQueryArgument(getContext(), theArgs[idx], null, null); 103 } 104 105 return retVal; 106 } 107 108 @Override 109 public Object invokeClientForBinary(String theResponseMimeType, InputStream theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) 110 throws IOException, BaseServerResponseException { 111 byte[] contents = IOUtils.toByteArray(theResponseReader); 112 113 IBaseBinary resource = (IBaseBinary) getContext().getResourceDefinition("Binary").newInstance(); 114 resource.setContentType(theResponseMimeType); 115 resource.setContent(contents); 116 117 switch (getMethodReturnType()) { 118 case LIST_OF_RESOURCES: 119 return Collections.singletonList(resource); 120 case RESOURCE: 121 return resource; 122 case BUNDLE_RESOURCE: 123 case METHOD_OUTCOME: 124 break; 125 } 126 127 throw new IllegalStateException("" + getMethodReturnType()); // should not happen 128 } 129 130 @Override 131 public boolean isBinary() { 132 return "Binary".equals(getResourceName()); 133 } 134 135 public boolean isVread() { 136 return mySupportsVersion; 137 } 138 139 public static HttpGetClientInvocation createAbsoluteReadInvocation(FhirContext theContext, IIdType theId) { 140 return new HttpGetClientInvocation(theContext, theId.toVersionless().getValue()); 141 } 142 143 public static HttpGetClientInvocation createAbsoluteVReadInvocation(FhirContext theContext, IIdType theId) { 144 return new HttpGetClientInvocation(theContext, theId.getValue()); 145 } 146 147 public static HttpGetClientInvocation createReadInvocation(FhirContext theContext, IIdType theId, String theResourceName) { 148 return new HttpGetClientInvocation(theContext, new IdDt(theResourceName, theId.getIdPart()).getValue()); 149 } 150 151 public static HttpGetClientInvocation createVReadInvocation(FhirContext theContext, IIdType theId, String theResourceName) { 152 return new HttpGetClientInvocation(theContext, new IdDt(theResourceName, theId.getIdPart(), theId.getVersionIdPart()).getValue()); 153 } 154 155 @Override 156 protected BundleTypeEnum getResponseBundleType() { 157 return null; 158 } 159 160}