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.HttpCacheInvalidator;
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 HttpCacheInvalidator httpCacheInvalidator;
57      private boolean deleteCache;
58  
59      public static CachingHttpClientBuilder create() {
60          return new CachingHttpClientBuilder();
61      }
62  
63      protected CachingHttpClientBuilder() {
64          super();
65          this.deleteCache = true;
66      }
67  
68      public final CachingHttpClientBuilder setResourceFactory(
69              final ResourceFactory resourceFactory) {
70          this.resourceFactory = resourceFactory;
71          return this;
72      }
73  
74      public final CachingHttpClientBuilder setHttpCacheStorage(final HttpCacheStorage storage) {
75          this.storage = storage;
76          return this;
77      }
78  
79      public final CachingHttpClientBuilder setCacheDir(final File cacheDir) {
80          this.cacheDir = cacheDir;
81          return this;
82      }
83  
84      public final CachingHttpClientBuilder setSchedulingStrategy(final SchedulingStrategy schedulingStrategy) {
85          this.schedulingStrategy = schedulingStrategy;
86          return this;
87      }
88  
89      public final CachingHttpClientBuilder setCacheConfig(final CacheConfig cacheConfig) {
90          this.cacheConfig = cacheConfig;
91          return this;
92      }
93  
94      public final CachingHttpClientBuilder setHttpCacheInvalidator(final HttpCacheInvalidator cacheInvalidator) {
95          this.httpCacheInvalidator = cacheInvalidator;
96          return this;
97      }
98  
99      public final CachingHttpClientBuilder setDeleteCache(final boolean deleteCache) {
100         this.deleteCache = deleteCache;
101         return this;
102     }
103 
104     @Override
105     protected void customizeExecChain(final NamedElementChain<ExecChainHandler> execChainDefinition) {
106         final CacheConfig config = this.cacheConfig != null ? this.cacheConfig : CacheConfig.DEFAULT;
107         // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
108         ResourceFactory resourceFactoryCopy = this.resourceFactory;
109         if (resourceFactoryCopy == null) {
110             if (this.cacheDir == null) {
111                 resourceFactoryCopy = new HeapResourceFactory();
112             } else {
113                 resourceFactoryCopy = new FileResourceFactory(cacheDir);
114             }
115         }
116         HttpCacheStorage storageCopy = this.storage;
117         if (storageCopy == null) {
118             if (this.cacheDir == null) {
119                 storageCopy = new BasicHttpCacheStorage(config);
120             } else {
121                 final ManagedHttpCacheStorage managedStorage = new ManagedHttpCacheStorage(config);
122                 if (this.deleteCache) {
123                     addCloseable(managedStorage::shutdown);
124                 } else {
125                     addCloseable(managedStorage);
126                 }
127                 storageCopy = managedStorage;
128             }
129         }
130         final HttpCache httpCache = new BasicHttpCache(
131                 resourceFactoryCopy,
132                 storageCopy,
133                 CacheKeyGenerator.INSTANCE,
134                 this.httpCacheInvalidator != null ? this.httpCacheInvalidator : new DefaultCacheInvalidator());
135 
136         DefaultCacheRevalidator cacheRevalidator = null;
137         if (config.getAsynchronousWorkers() > 0) {
138             final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(config.getAsynchronousWorkers());
139             addCloseable(executorService::shutdownNow);
140             cacheRevalidator = new DefaultCacheRevalidator(
141                     executorService,
142                     this.schedulingStrategy != null ? this.schedulingStrategy : ImmediateSchedulingStrategy.INSTANCE);
143         }
144         final CachingExec cachingExec = new CachingExec(
145                 httpCache,
146                 cacheRevalidator,
147                 config);
148         execChainDefinition.addBefore(ChainElement.PROTOCOL.name(), cachingExec, ChainElement.CACHING.name());
149     }
150 
151 }