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