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.interceptor.partition;
021
022import ca.uhn.fhir.i18n.Msg;
023import ca.uhn.fhir.interceptor.api.Hook;
024import ca.uhn.fhir.interceptor.api.Interceptor;
025import ca.uhn.fhir.interceptor.api.Pointcut;
026import ca.uhn.fhir.interceptor.model.RequestPartitionId;
027import ca.uhn.fhir.rest.api.server.RequestDetails;
028import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
029import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
030import ca.uhn.fhir.rest.server.tenant.ITenantIdentificationStrategy;
031import jakarta.annotation.Nonnull;
032
033import static org.apache.commons.lang3.StringUtils.isBlank;
034
035/**
036 * This interceptor uses the request tenant ID (as supplied to the server using
037 * {@link ca.uhn.fhir.rest.server.RestfulServer#setTenantIdentificationStrategy(ITenantIdentificationStrategy)}
038 * to indicate the partition ID. With this interceptor registered, The server treats the tenant name
039 * supplied by the {@link ITenantIdentificationStrategy tenant identification strategy} as a partition name.
040 * <p>
041 * Partition names (aka tenant IDs) must be registered in advance using the partition management operations.
042 * </p>
043 *
044 * @since 5.0.0
045 */
046@Interceptor
047public class RequestTenantPartitionInterceptor {
048
049        @Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY)
050        public RequestPartitionId partitionIdentifyCreate(RequestDetails theRequestDetails) {
051                return extractPartitionIdFromRequest(theRequestDetails);
052        }
053
054        @Nonnull
055        protected RequestPartitionId extractPartitionIdFromRequest(RequestDetails theRequestDetails) {
056
057                // We will use the tenant ID that came from the request as the partition name
058                String tenantId = theRequestDetails.getTenantId();
059                if (isBlank(tenantId)) {
060                        if (theRequestDetails instanceof SystemRequestDetails) {
061                                SystemRequestDetails requestDetails = (SystemRequestDetails) theRequestDetails;
062                                if (requestDetails.getRequestPartitionId() != null) {
063                                        return requestDetails.getRequestPartitionId();
064                                }
065                                return RequestPartitionId.defaultPartition();
066                        }
067                        throw new InternalErrorException(Msg.code(343) + "No partition ID has been specified");
068                }
069
070                return RequestPartitionId.fromPartitionName(tenantId);
071        }
072}