001package ca.uhn.fhir.rest.server.method;
002
003/*
004 * #%L
005 * HAPI FHIR - Server 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.lang.annotation.Annotation;
025import java.lang.reflect.Method;
026import java.util.Arrays;
027import java.util.Collections;
028import java.util.ListIterator;
029import java.util.Set;
030
031import org.hl7.fhir.instance.model.api.IIdType;
032
033import ca.uhn.fhir.context.ConfigurationException;
034import ca.uhn.fhir.context.FhirContext;
035import ca.uhn.fhir.rest.annotation.Patch;
036import ca.uhn.fhir.rest.annotation.ResourceParam;
037import ca.uhn.fhir.rest.api.PatchTypeEnum;
038import ca.uhn.fhir.rest.api.RequestTypeEnum;
039import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
040import ca.uhn.fhir.rest.api.server.RequestDetails;
041
042import javax.annotation.Nonnull;
043
044/**
045 * Base class for an operation that has a resource type but not a resource body in the
046 * request body
047 *
048 */
049public class PatchMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceIdButNoResourceBody {
050
051        private int myPatchTypeParameterIndex = -1;
052        private int myResourceParamIndex;
053
054        public PatchMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
055                super(theMethod, theContext, theProvider, Patch.class, theMethod.getAnnotation(Patch.class).type());
056
057                for (ListIterator<Class<?>> iter = Arrays.asList(theMethod.getParameterTypes()).listIterator(); iter.hasNext();) {
058                        int nextIndex = iter.nextIndex();
059                        Class<?> next = iter.next();
060                        if (next.equals(PatchTypeEnum.class)) {
061                                myPatchTypeParameterIndex = nextIndex;
062                        }
063                        for (Annotation nextAnnotation : theMethod.getParameterAnnotations()[nextIndex]) {
064                                if (nextAnnotation instanceof ResourceParam) {
065                                        myResourceParamIndex = nextIndex;
066                                }
067                        }
068                }
069
070                if (myPatchTypeParameterIndex == -1) {
071                        throw new ConfigurationException(Msg.code(370) + "Method has no parameter of type " + PatchTypeEnum.class.getName() + " - " + theMethod.toString());
072                }
073                if (myResourceParamIndex == -1) {
074                        throw new ConfigurationException(Msg.code(371) + "Method has no parameter with @" + ResourceParam.class.getSimpleName() + " annotation - " + theMethod.toString());
075                }
076        }
077
078        @Override
079        protected boolean allowVoidReturnType() {
080                return true;
081        }
082
083        @Override
084        public MethodMatchEnum incomingServerRequestMatchesMethod(RequestDetails theRequest) {
085                MethodMatchEnum retVal = super.incomingServerRequestMatchesMethod(theRequest);
086                if (retVal.ordinal() > MethodMatchEnum.NONE.ordinal()) {
087                        PatchTypeParameter.getTypeForRequestOrThrowInvalidRequestException(theRequest);
088                }
089                return retVal;
090        }
091
092        @Nonnull
093        @Override
094        public RestOperationTypeEnum getRestOperationType() {
095                return RestOperationTypeEnum.PATCH;
096        }
097
098        @Override
099        protected Set<RequestTypeEnum> provideAllowableRequestTypes() {
100                return Collections.singleton(RequestTypeEnum.PATCH);
101        }
102
103
104
105        @Override
106        protected void addParametersForServerRequest(RequestDetails theRequest, Object[] theParams) {
107                IIdType id = theRequest.getId();
108                id = UpdateMethodBinding.applyETagAsVersion(theRequest, id);
109                theParams[getIdParameterIndex()] = id;
110        }
111
112        @Override
113        protected String getMatchingOperation() {
114                return null;
115        }
116
117
118}