001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.http.client.support;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import org.springframework.core.annotation.AnnotationAwareOrderComparator;
023import org.springframework.http.client.ClientHttpRequestFactory;
024import org.springframework.http.client.ClientHttpRequestInterceptor;
025import org.springframework.http.client.InterceptingClientHttpRequestFactory;
026import org.springframework.lang.Nullable;
027import org.springframework.util.Assert;
028import org.springframework.util.CollectionUtils;
029
030/**
031 * Base class for {@link org.springframework.web.client.RestTemplate}
032 * and other HTTP accessing gateway helpers, adding interceptor-related
033 * properties to {@link HttpAccessor}'s common properties.
034 *
035 * <p>Not intended to be used directly.
036 * See {@link org.springframework.web.client.RestTemplate} for an entry point.
037 *
038 * @author Arjen Poutsma
039 * @author Juergen Hoeller
040 * @since 3.0
041 * @see ClientHttpRequestInterceptor
042 * @see InterceptingClientHttpRequestFactory
043 * @see org.springframework.web.client.RestTemplate
044 */
045public abstract class InterceptingHttpAccessor extends HttpAccessor {
046
047        private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
048
049        @Nullable
050        private volatile ClientHttpRequestFactory interceptingRequestFactory;
051
052
053        /**
054         * Set the request interceptors that this accessor should use.
055         * <p>The interceptors will get immediately sorted according to their
056         * {@linkplain AnnotationAwareOrderComparator#sort(List) order}.
057         * @see #getRequestFactory()
058         * @see AnnotationAwareOrderComparator
059         */
060        public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
061                Assert.noNullElements(interceptors, "'interceptors' must not contain null elements");
062                // Take getInterceptors() List as-is when passed in here
063                if (this.interceptors != interceptors) {
064                        this.interceptors.clear();
065                        this.interceptors.addAll(interceptors);
066                        AnnotationAwareOrderComparator.sort(this.interceptors);
067                }
068        }
069
070        /**
071         * Get the request interceptors that this accessor uses.
072         * <p>The returned {@link List} is active and may be modified. Note,
073         * however, that the interceptors will not be resorted according to their
074         * {@linkplain AnnotationAwareOrderComparator#sort(List) order} before the
075         * {@link ClientHttpRequestFactory} is built.
076         */
077        public List<ClientHttpRequestInterceptor> getInterceptors() {
078                return this.interceptors;
079        }
080
081        /**
082         * {@inheritDoc}
083         */
084        @Override
085        public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
086                super.setRequestFactory(requestFactory);
087                this.interceptingRequestFactory = null;
088        }
089
090        /**
091         * Overridden to expose an {@link InterceptingClientHttpRequestFactory}
092         * if necessary.
093         * @see #getInterceptors()
094         */
095        @Override
096        public ClientHttpRequestFactory getRequestFactory() {
097                List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
098                if (!CollectionUtils.isEmpty(interceptors)) {
099                        ClientHttpRequestFactory factory = this.interceptingRequestFactory;
100                        if (factory == null) {
101                                factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
102                                this.interceptingRequestFactory = factory;
103                        }
104                        return factory;
105                }
106                else {
107                        return super.getRequestFactory();
108                }
109        }
110
111}