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.async.AsyncExecChainHandler;
34  import org.apache.hc.client5.http.cache.HttpAsyncCacheStorage;
35  import org.apache.hc.client5.http.cache.HttpAsyncCacheStorageAdaptor;
36  import org.apache.hc.client5.http.cache.HttpCacheEntryFactory;
37  import org.apache.hc.client5.http.cache.HttpCacheStorage;
38  import org.apache.hc.client5.http.cache.ResourceFactory;
39  import org.apache.hc.client5.http.impl.ChainElement;
40  import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder;
41  import org.apache.hc.client5.http.impl.schedule.ImmediateSchedulingStrategy;
42  import org.apache.hc.client5.http.schedule.SchedulingStrategy;
43  import org.apache.hc.core5.annotation.Experimental;
44  import org.apache.hc.core5.http.config.NamedElementChain;
45  
46  /**
47   * Builder for HTTP/2 {@link org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient}
48   * instances capable of client-side caching.
49   *
50   * @since 5.0
51   */
52  @Experimental
53  public class CachingH2AsyncClientBuilder extends H2AsyncClientBuilder {
54  
55      private ResourceFactory resourceFactory;
56      private HttpAsyncCacheStorage storage;
57      private File cacheDir;
58      private SchedulingStrategy schedulingStrategy;
59      private CacheConfig cacheConfig;
60      private boolean deleteCache;
61  
62      public static CachingH2AsyncClientBuilder create() {
63          return new CachingH2AsyncClientBuilder();
64      }
65  
66      protected CachingH2AsyncClientBuilder() {
67          super();
68          addResponseInterceptorFirst(ResponseCacheConformance.INSTANCE);
69          addResponseInterceptorLast(ResponseViaCache.INSTANCE);
70          addRequestInterceptorLast(RequestViaCache.INSTANCE);
71          this.deleteCache = true;
72      }
73  
74      public final CachingH2AsyncClientBuilder setResourceFactory(final ResourceFactory resourceFactory) {
75          this.resourceFactory = resourceFactory;
76          return this;
77      }
78  
79      public final CachingH2AsyncClientBuilder setHttpCacheStorage(final HttpCacheStorage storage) {
80          this.storage = storage != null ? new HttpAsyncCacheStorageAdaptor(storage) : null;
81          return this;
82      }
83  
84      public final CachingH2AsyncClientBuilder setHttpCacheStorage(final HttpAsyncCacheStorage storage) {
85          this.storage = storage;
86          return this;
87      }
88  
89      public final CachingH2AsyncClientBuilder setCacheDir(final File cacheDir) {
90          this.cacheDir = cacheDir;
91          return this;
92      }
93  
94      public final CachingH2AsyncClientBuilder setSchedulingStrategy(final SchedulingStrategy schedulingStrategy) {
95          this.schedulingStrategy = schedulingStrategy;
96          return this;
97      }
98  
99      public final CachingH2AsyncClientBuilder setCacheConfig(final CacheConfig cacheConfig) {
100         this.cacheConfig = cacheConfig;
101         return this;
102     }
103 
104     /**
105      * @deprecated Do not use.
106      */
107     @Deprecated
108     public final CachingH2AsyncClientBuilder setHttpCacheInvalidator(final org.apache.hc.client5.http.cache.HttpAsyncCacheInvalidator cacheInvalidator) {
109         return this;
110     }
111 
112     public CachingH2AsyncClientBuilder setDeleteCache(final boolean deleteCache) {
113         this.deleteCache = deleteCache;
114         return this;
115     }
116 
117     @Override
118     protected void customizeExecChain(final NamedElementChain<AsyncExecChainHandler> execChainDefinition) {
119         final CacheConfig config = this.cacheConfig != null ? this.cacheConfig : CacheConfig.DEFAULT;
120         // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
121         ResourceFactory resourceFactoryCopy = this.resourceFactory;
122         if (resourceFactoryCopy == null) {
123             if (this.cacheDir == null) {
124                 resourceFactoryCopy = new HeapResourceFactory();
125             } else {
126                 resourceFactoryCopy = new FileResourceFactory(cacheDir);
127             }
128         }
129         HttpAsyncCacheStorage storageCopy = this.storage;
130         if (storageCopy == null) {
131             if (this.cacheDir == null) {
132                 storageCopy = new HttpAsyncCacheStorageAdaptor(new BasicHttpCacheStorage(config));
133             } else {
134                 final ManagedHttpCacheStorage managedStorage = new ManagedHttpCacheStorage(config);
135                 if (this.deleteCache) {
136                     addCloseable(managedStorage::shutdown);
137                 } else {
138                     addCloseable(managedStorage);
139                 }
140                 storageCopy = new HttpAsyncCacheStorageAdaptor(managedStorage);
141             }
142         }
143         final HttpAsyncCache httpCache = new BasicHttpAsyncCache(
144                 resourceFactoryCopy,
145                 HttpCacheEntryFactory.INSTANCE,
146                 storageCopy,
147                 CacheKeyGenerator.INSTANCE);
148 
149         DefaultAsyncCacheRevalidator cacheRevalidator = null;
150         if (config.getAsynchronousWorkers() > 0) {
151             final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(config.getAsynchronousWorkers());
152             addCloseable(executorService::shutdownNow);
153             cacheRevalidator = new DefaultAsyncCacheRevalidator(
154                     executorService,
155                     this.schedulingStrategy != null ? this.schedulingStrategy : ImmediateSchedulingStrategy.INSTANCE);
156         }
157 
158         final AsyncCachingExec cachingExec = new AsyncCachingExec(
159                 httpCache,
160                 cacheRevalidator,
161                 config);
162         execChainDefinition.addBefore(ChainElement.PROTOCOL.name(), cachingExec, ChainElement.CACHING.name());
163     }
164 
165 }