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}