001/*-
002 * #%L
003 * HAPI FHIR - Client 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.client.interceptor;
021
022import ca.uhn.fhir.interceptor.api.Hook;
023import ca.uhn.fhir.interceptor.api.Pointcut;
024import ca.uhn.fhir.rest.client.api.IHttpRequest;
025import ca.uhn.fhir.rest.client.api.IRestfulClient;
026import ca.uhn.fhir.rest.client.api.UrlSourceEnum;
027import org.apache.commons.lang3.Validate;
028
029import static org.apache.commons.lang3.StringUtils.isBlank;
030
031/**
032 * This interceptor adds a path element representing the tenant ID to each client request. It is primarily
033 * intended to be used with clients that are accessing servers using
034 * <a href="https://hapifhir.io/hapi-fhir/docs/server_plain/multitenancy.html#url-base-multitenancy">URL Base Multitenancy</a>.
035 */
036public class UrlTenantSelectionInterceptor {
037
038        private String myTenantId;
039
040        /**
041         * Constructor
042         */
043        public UrlTenantSelectionInterceptor() {
044                this(null);
045        }
046
047        /**
048         * Constructor
049         *
050         * @param theTenantId The tenant ID to add to URL base
051         */
052        public UrlTenantSelectionInterceptor(String theTenantId) {
053                myTenantId = theTenantId;
054        }
055
056        /**
057         * Returns the tenant ID
058         */
059        public String getTenantId() {
060                return myTenantId;
061        }
062
063        /**
064         * Sets the tenant ID
065         */
066        public void setTenantId(String theTenantId) {
067                myTenantId = theTenantId;
068        }
069
070        @Hook(value = Pointcut.CLIENT_REQUEST, order = InterceptorOrders.URL_TENANT_SELECTION_INTERCEPTOR_REQUEST)
071        public void request(IRestfulClient theClient, IHttpRequest theRequest) {
072                String tenantId = getTenantId();
073                if (isBlank(tenantId)) {
074                        return;
075                }
076                String requestUri = theRequest.getUri();
077                String serverBase = theClient.getServerBase();
078                if (serverBase.endsWith("/")) {
079                        serverBase = serverBase.substring(0, serverBase.length() - 1);
080                }
081
082                Validate.isTrue(
083                                requestUri.startsWith(serverBase),
084                                "Request URI %s does not start with server base %s",
085                                requestUri,
086                                serverBase);
087
088                if (theRequest.getUrlSource() == UrlSourceEnum.EXPLICIT) {
089                        return;
090                }
091
092                String newUri = serverBase + "/" + tenantId + requestUri.substring(serverBase.length());
093                theRequest.setUri(newUri);
094        }
095}