View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.client5.http.impl.cache;
28  
29  import java.io.File;
30  import java.util.concurrent.ScheduledExecutorService;
31  import java.util.concurrent.ScheduledThreadPoolExecutor;
32  
33  import org.apache.hc.client5.http.cache.HttpCacheEntryFactory;
34  import org.apache.hc.client5.http.cache.HttpCacheStorage;
35  import org.apache.hc.client5.http.cache.ResourceFactory;
36  import org.apache.hc.client5.http.classic.ExecChainHandler;
37  import org.apache.hc.client5.http.impl.ChainElement;
38  import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
39  import org.apache.hc.client5.http.impl.schedule.ImmediateSchedulingStrategy;
40  import org.apache.hc.client5.http.schedule.SchedulingStrategy;
41  import org.apache.hc.core5.http.config.NamedElementChain;
42  
43  /**
44   * Builder for {@link org.apache.hc.client5.http.impl.classic.CloseableHttpClient}
45   * instances capable of client-side caching.
46   *
47   * @since 4.3
48   */
49  public class CachingHttpClientBuilder extends HttpClientBuilder {
50  
51      private ResourceFactory resourceFactory;
52      private HttpCacheStorage storage;
53      private File cacheDir;
54      private SchedulingStrategy schedulingStrategy;
55      private CacheConfig cacheConfig;
56      private boolean deleteCache;
57  
58      public static CachingHttpClientBuilder create() {
59          return new CachingHttpClientBuilder();
60      }
61  
62      protected CachingHttpClientBuilder() {
63          super();
64          addResponseInterceptorFirst(ResponseCacheConformance.INSTANCE);
65          addResponseInterceptorLast(ResponseViaCache.INSTANCE);
66          addRequestInterceptorLast(RequestViaCache.INSTANCE);
67          this.deleteCache = true;
68      }
69  
70      public final CachingHttpClientBuilder setResourceFactory(
71              final ResourceFactory resourceFactory) {
72          this.resourceFactory = resourceFactory;
73          return this;
74      }
75  
76      public final CachingHttpClientBuilder setHttpCacheStorage(final HttpCacheStorage storage) {
77          this.storage = storage;
78          return this;
79      }
80  
81      public final CachingHttpClientBuilder setCacheDir(final File cacheDir) {
82          this.cacheDir = cacheDir;
83          return this;
84      }
85  
86      public final CachingHttpClientBuilder setSchedulingStrategy(final SchedulingStrategy schedulingStrategy) {
87          this.schedulingStrategy = schedulingStrategy;
88          return this;
89      }
90  
91      public final CachingHttpClientBuilder setCacheConfig(final CacheConfig cacheConfig) {
92          this.cacheConfig = cacheConfig;
93          return this;
94      }
95  
96      /**
97       * @deprecated Do not use.
98       */
99      @Deprecated
100     public final CachingHttpClientBuilder setHttpCacheInvalidator(final org.apache.hc.client5.http.cache.HttpCacheInvalidator cacheInvalidator) {
101         return this;
102     }
103 
104     public final CachingHttpClientBuilder setDeleteCache(final boolean deleteCache) {
105         this.deleteCache = deleteCache;
106         return this;
107     }
108 
109     @Override
110     protected void customizeExecChain(final NamedElementChain<ExecChainHandler> execChainDefinition) {
111         final CacheConfig config = this.cacheConfig != null ? this.cacheConfig : CacheConfig.DEFAULT;
112         // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
113         ResourceFactory resourceFactoryCopy = this.resourceFactory;
114         if (resourceFactoryCopy == null) {
115             if (this.cacheDir == null) {
116                 resourceFactoryCopy = new HeapResourceFactory();
117             } else {
118                 resourceFactoryCopy = new FileResourceFactory(cacheDir);
119             }
120         }
121         HttpCacheStorage storageCopy = this.storage;
122         if (storageCopy == null) {
123             if (this.cacheDir == null) {
124                 storageCopy = new BasicHttpCacheStorage(config);
125             } else {
126                 final ManagedHttpCacheStorage managedStorage = new ManagedHttpCacheStorage(config);
127                 if (this.deleteCache) {
128                     addCloseable(managedStorage::shutdown);
129                 } else {
130                     addCloseable(managedStorage);
131                 }
132                 storageCopy = managedStorage;
133             }
134         }
135         final HttpCache httpCache = new BasicHttpCache(
136                 resourceFactoryCopy,
137                 HttpCacheEntryFactory.INSTANCE,
138                 storageCopy,
139                 CacheKeyGenerator.INSTANCE);
140 
141         DefaultCacheRevalidator cacheRevalidator = null;
142         if (config.getAsynchronousWorkers() > 0) {
143             final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(config.getAsynchronousWorkers());
144             addCloseable(executorService::shutdownNow);
145             cacheRevalidator = new DefaultCacheRevalidator(
146                     executorService,
147                     this.schedulingStrategy != null ? this.schedulingStrategy : ImmediateSchedulingStrategy.INSTANCE);
148         }
149         final CachingExec cachingExec = new CachingExec(
150                 httpCache,
151                 cacheRevalidator,
152                 config);
153         execChainDefinition.addBefore(ChainElement.PROTOCOL.name(), cachingExec, ChainElement.CACHING.name());
154     }
155 
156 }