001/*
002 * #%L
003 * HAPI FHIR - Server 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.server.method;
021
022import ca.uhn.fhir.context.FhirContext;
023import ca.uhn.fhir.i18n.Msg;
024import ca.uhn.fhir.rest.annotation.Update;
025import ca.uhn.fhir.rest.api.Constants;
026import ca.uhn.fhir.rest.api.RequestTypeEnum;
027import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
028import ca.uhn.fhir.rest.api.server.RequestDetails;
029import ca.uhn.fhir.rest.param.ParameterUtil;
030import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
031import jakarta.annotation.Nonnull;
032import org.hl7.fhir.instance.model.api.IBaseResource;
033import org.hl7.fhir.instance.model.api.IIdType;
034
035import java.lang.reflect.Method;
036import java.util.Collections;
037import java.util.Set;
038
039import static org.apache.commons.lang3.StringUtils.isBlank;
040import static org.apache.commons.lang3.StringUtils.isNotBlank;
041
042public class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {
043
044        public UpdateMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
045                super(theMethod, theContext, Update.class, theProvider);
046        }
047
048        @Override
049        protected void addParametersForServerRequest(RequestDetails theRequest, Object[] theParams) {
050                IIdType id = theRequest.getId();
051                id = applyETagAsVersion(theRequest, id);
052                if (theRequest.getId() != null && theRequest.getId().hasVersionIdPart() == false) {
053                        if (id != null && id.hasVersionIdPart()) {
054                                theRequest.getId().setValue(id.getValue());
055                        }
056                }
057                super.addParametersForServerRequest(theRequest, theParams);
058        }
059
060        public static IIdType applyETagAsVersion(RequestDetails theRequest, IIdType theId) {
061                String ifMatchValue = theRequest.getHeader(Constants.HEADER_IF_MATCH);
062                return applyETagAsVersion(ifMatchValue, theId);
063        }
064
065        public static IIdType applyETagAsVersion(String theIfMatchValue, IIdType theId) {
066                if (isNotBlank(theIfMatchValue)) {
067                        theIfMatchValue = ParameterUtil.parseETagValue(theIfMatchValue);
068                        if (theId != null && theId.hasVersionIdPart() == false) {
069                                theId = theId.withVersion(theIfMatchValue);
070                        }
071                }
072                return theId;
073        }
074
075        @Override
076        protected String getMatchingOperation() {
077                return null;
078        }
079
080        @Nonnull
081        @Override
082        public RestOperationTypeEnum getRestOperationType() {
083                return RestOperationTypeEnum.UPDATE;
084        }
085
086        /*
087         * @Override public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) { if
088         * (super.incomingServerRequestMatchesMethod(theRequest)) { if (myVersionIdParameterIndex != null) { if
089         * (theRequest.getVersionId() == null) { return false; } } else { if (theRequest.getVersionId() != null) { return
090         * false; } } return true; } else { return false; } }
091         */
092
093        @Override
094        protected Set<RequestTypeEnum> provideAllowableRequestTypes() {
095                return Collections.singleton(RequestTypeEnum.PUT);
096        }
097
098        @Override
099        protected void validateResourceIdAndUrlIdForNonConditionalOperation(
100                        IBaseResource theResource, String theResourceId, String theUrlId, String theMatchUrl) {
101                if (isBlank(theMatchUrl)) {
102                        if (isBlank(theUrlId)) {
103                                String msg = getContext()
104                                                .getLocalizer()
105                                                .getMessage(BaseOutcomeReturningMethodBindingWithResourceParam.class, "noIdInUrlForUpdate");
106                                throw new InvalidRequestException(Msg.code(418) + msg);
107                        }
108                        if (isBlank(theResourceId)) {
109                                String msg = getContext()
110                                                .getLocalizer()
111                                                .getMessage(BaseOutcomeReturningMethodBindingWithResourceParam.class, "noIdInBodyForUpdate");
112                                throw new InvalidRequestException(Msg.code(419) + msg);
113                        }
114                        if (!theResourceId.equals(theUrlId)) {
115                                String msg = getContext()
116                                                .getLocalizer()
117                                                .getMessage(
118                                                                BaseOutcomeReturningMethodBindingWithResourceParam.class,
119                                                                "incorrectIdForUpdate",
120                                                                theResourceId,
121                                                                theUrlId);
122                                throw new InvalidRequestException(Msg.code(420) + msg);
123                        }
124                } else {
125                        theResource.setId((IIdType) null);
126                }
127        }
128}