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}