001/* 002 * #%L 003 * HAPI FHIR - Client Framework 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.rest.client.method; 021 022import ca.uhn.fhir.context.ConfigurationException; 023import ca.uhn.fhir.context.FhirContext; 024import ca.uhn.fhir.i18n.Msg; 025import ca.uhn.fhir.model.primitive.IdDt; 026import ca.uhn.fhir.model.valueset.BundleTypeEnum; 027import ca.uhn.fhir.rest.annotation.Elements; 028import ca.uhn.fhir.rest.annotation.IdParam; 029import ca.uhn.fhir.rest.annotation.Read; 030import ca.uhn.fhir.rest.api.RestOperationTypeEnum; 031import ca.uhn.fhir.rest.param.ParameterUtil; 032import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; 033import org.apache.commons.io.IOUtils; 034import org.apache.commons.lang3.Validate; 035import org.hl7.fhir.instance.model.api.IBaseBinary; 036import org.hl7.fhir.instance.model.api.IBaseResource; 037import org.hl7.fhir.instance.model.api.IIdType; 038 039import java.io.IOException; 040import java.io.InputStream; 041import java.lang.reflect.Method; 042import java.util.ArrayList; 043import java.util.Collections; 044import java.util.List; 045import java.util.Map; 046 047public class ReadMethodBinding extends BaseResourceReturningMethodBinding 048 implements IClientResponseHandlerHandlesBinary<Object> { 049 private Integer myIdIndex; 050 private boolean mySupportsVersion; 051 private Class<? extends IIdType> myIdParameterType; 052 053 @SuppressWarnings("unchecked") 054 public ReadMethodBinding( 055 Class<? extends IBaseResource> theAnnotatedResourceType, 056 Method theMethod, 057 FhirContext theContext, 058 Object theProvider) { 059 super(theAnnotatedResourceType, theMethod, theContext, theProvider); 060 061 Validate.notNull(theMethod, "Method must not be null"); 062 063 Integer idIndex = ParameterUtil.findIdParameterIndex(theMethod, getContext()); 064 065 Class<?>[] parameterTypes = theMethod.getParameterTypes(); 066 067 mySupportsVersion = theMethod.getAnnotation(Read.class).version(); 068 myIdIndex = idIndex; 069 070 if (myIdIndex == null) { 071 throw new ConfigurationException( 072 Msg.code(1423) + "@" + Read.class.getSimpleName() + " method " + theMethod.getName() + " on type \"" 073 + theMethod.getDeclaringClass().getName() + "\" does not have a parameter annotated with @" 074 + IdParam.class.getSimpleName()); 075 } 076 myIdParameterType = (Class<? extends IIdType>) parameterTypes[myIdIndex]; 077 078 if (!IIdType.class.isAssignableFrom(myIdParameterType)) { 079 throw new ConfigurationException( 080 Msg.code(1424) + "ID parameter must be of type IdDt or IdType - Found: " + myIdParameterType); 081 } 082 } 083 084 @Override 085 public List<Class<?>> getAllowableParamAnnotations() { 086 ArrayList<Class<?>> retVal = new ArrayList<Class<?>>(); 087 retVal.add(IdParam.class); 088 retVal.add(Elements.class); 089 return retVal; 090 } 091 092 @Override 093 public RestOperationTypeEnum getRestOperationType() { 094 return isVread() ? RestOperationTypeEnum.VREAD : RestOperationTypeEnum.READ; 095 } 096 097 @Override 098 public ReturnTypeEnum getReturnType() { 099 return ReturnTypeEnum.RESOURCE; 100 } 101 102 @Override 103 public HttpGetClientInvocation invokeClient(Object[] theArgs) { 104 HttpGetClientInvocation retVal; 105 IIdType id = ((IIdType) theArgs[myIdIndex]); 106 String resourceName = getResourceName(); 107 if (id.hasVersionIdPart()) { 108 retVal = createVReadInvocation( 109 getContext(), new IdDt(resourceName, id.getIdPart(), id.getVersionIdPart()), resourceName); 110 } else { 111 retVal = createReadInvocation(getContext(), id, resourceName); 112 } 113 114 for (int idx = 0; idx < theArgs.length; idx++) { 115 IParameter nextParam = getParameters().get(idx); 116 nextParam.translateClientArgumentIntoQueryArgument(getContext(), theArgs[idx], null, null); 117 } 118 119 return retVal; 120 } 121 122 @Override 123 public Object invokeClientForBinary( 124 String theResponseMimeType, 125 InputStream theResponseReader, 126 int theResponseStatusCode, 127 Map<String, List<String>> theHeaders) 128 throws IOException, BaseServerResponseException { 129 byte[] contents = IOUtils.toByteArray(theResponseReader); 130 131 IBaseBinary resource = 132 (IBaseBinary) getContext().getResourceDefinition("Binary").newInstance(); 133 resource.setContentType(theResponseMimeType); 134 resource.setContent(contents); 135 136 switch (getMethodReturnType()) { 137 case LIST_OF_RESOURCES: 138 return Collections.singletonList(resource); 139 case RESOURCE: 140 return resource; 141 case BUNDLE_RESOURCE: 142 case METHOD_OUTCOME: 143 break; 144 } 145 146 throw new IllegalStateException(Msg.code(1425) + "" + getMethodReturnType()); // should not happen 147 } 148 149 @Override 150 public boolean isBinary() { 151 return "Binary".equals(getResourceName()); 152 } 153 154 public boolean isVread() { 155 return mySupportsVersion; 156 } 157 158 public static HttpGetClientInvocation createAbsoluteReadInvocation(FhirContext theContext, IIdType theId) { 159 return new HttpGetClientInvocation(theContext, theId.toVersionless().getValue()); 160 } 161 162 public static HttpGetClientInvocation createAbsoluteVReadInvocation(FhirContext theContext, IIdType theId) { 163 return new HttpGetClientInvocation(theContext, theId.getValue()); 164 } 165 166 public static HttpGetClientInvocation createReadInvocation( 167 FhirContext theContext, IIdType theId, String theResourceName) { 168 return new HttpGetClientInvocation(theContext, new IdDt(theResourceName, theId.getIdPart()).getValue()); 169 } 170 171 public static HttpGetClientInvocation createVReadInvocation( 172 FhirContext theContext, IIdType theId, String theResourceName) { 173 return new HttpGetClientInvocation( 174 theContext, new IdDt(theResourceName, theId.getIdPart(), theId.getVersionIdPart()).getValue()); 175 } 176 177 @Override 178 protected BundleTypeEnum getResponseBundleType() { 179 return null; 180 } 181}