001package ca.uhn.fhir.rest.client.method;
002
003/*
004 * #%L
005 * HAPI FHIR - Client Framework
006 * %%
007 * Copyright (C) 2014 - 2018 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 */
022import static org.apache.commons.lang3.StringUtils.isBlank;
023import static org.apache.commons.lang3.StringUtils.isNotBlank;
024
025import java.lang.reflect.Method;
026import java.lang.reflect.Modifier;
027import java.util.Date;
028
029import org.hl7.fhir.instance.model.api.*;
030
031import ca.uhn.fhir.context.FhirContext;
032import ca.uhn.fhir.model.api.IResource;
033import ca.uhn.fhir.model.valueset.BundleTypeEnum;
034import ca.uhn.fhir.rest.annotation.History;
035import ca.uhn.fhir.rest.api.Constants;
036import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
037import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
038import ca.uhn.fhir.rest.param.ParameterUtil;
039import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
040
041public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
042
043        private final Integer myIdParamIndex;
044        private String myResourceName;
045        private final RestOperationTypeEnum myResourceOperationType;
046
047        public HistoryMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
048                super(toReturnType(theMethod, theProvider), theMethod, theContext, theProvider);
049
050                myIdParamIndex = ParameterUtil.findIdParameterIndex(theMethod, getContext());
051
052                History historyAnnotation = theMethod.getAnnotation(History.class);
053                Class<? extends IBaseResource> type = historyAnnotation.type();
054                if (Modifier.isInterface(type.getModifiers())) {
055                        myResourceOperationType = RestOperationTypeEnum.HISTORY_SYSTEM;
056                } else {
057                        if (myIdParamIndex != null) {
058                                myResourceOperationType = RestOperationTypeEnum.HISTORY_INSTANCE;
059                        } else {
060                                myResourceOperationType = RestOperationTypeEnum.HISTORY_TYPE;
061                        }
062                }
063
064                if (type != IBaseResource.class && type != IResource.class) {
065                        myResourceName = theContext.getResourceDefinition(type).getName();
066                } else {
067                        myResourceName = null;
068                }
069
070        }
071
072        @Override
073        public RestOperationTypeEnum getRestOperationType() {
074                return myResourceOperationType;
075        }
076
077        @Override
078        protected BundleTypeEnum getResponseBundleType() {
079                return BundleTypeEnum.HISTORY;
080        }
081
082        @Override
083        public ReturnTypeEnum getReturnType() {
084                return ReturnTypeEnum.BUNDLE;
085        }
086
087        @Override
088        public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
089                IIdType id = null;
090                String resourceName = myResourceName;
091                if (myIdParamIndex != null) {
092                        id = (IIdType) theArgs[myIdParamIndex];
093                        if (id == null || isBlank(id.getValue())) {
094                                throw new NullPointerException("ID can not be null");
095                        }
096                }
097
098                String historyId = id != null ? id.getIdPart() : null;
099                HttpGetClientInvocation retVal = createHistoryInvocation(getContext(), resourceName, historyId, null, null);
100
101                if (theArgs != null) {
102                        for (int idx = 0; idx < theArgs.length; idx++) {
103                                IParameter nextParam = getParameters().get(idx);
104                                nextParam.translateClientArgumentIntoQueryArgument(getContext(), theArgs[idx], retVal.getParameters(), null);
105                        }
106                }
107
108                return retVal;
109        }
110
111        public static HttpGetClientInvocation createHistoryInvocation(FhirContext theContext, String theResourceName, String theId, IPrimitiveType<Date> theSince, Integer theLimit) {
112                StringBuilder b = new StringBuilder();
113                if (theResourceName != null) {
114                        b.append(theResourceName);
115                        if (isNotBlank(theId)) {
116                                b.append('/');
117                                b.append(theId);
118                        }
119                }
120                if (b.length() > 0) {
121                        b.append('/');
122                }
123                b.append(Constants.PARAM_HISTORY);
124
125                boolean haveParam = false;
126                if (theSince != null && !theSince.isEmpty()) {
127                        haveParam = true;
128                        b.append('?').append(Constants.PARAM_SINCE).append('=').append(theSince.getValueAsString());
129                }
130                if (theLimit != null) {
131                        b.append(haveParam ? '&' : '?');
132                        b.append(Constants.PARAM_COUNT).append('=').append(theLimit);
133                }
134
135                HttpGetClientInvocation retVal = new HttpGetClientInvocation(theContext, b.toString());
136                return retVal;
137        }
138
139        private static Class<? extends IBaseResource> toReturnType(Method theMethod, Object theProvider) {
140                History historyAnnotation = theMethod.getAnnotation(History.class);
141                Class<? extends IBaseResource> type = historyAnnotation.type();
142                if (type != IBaseResource.class && type != IResource.class) {
143                        return type;
144                }
145                return null;
146        }
147
148}