View Javadoc
1   /* 
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   *
14   */
15  
16  package org.esigate.http;
17  
18  import java.io.IOException;
19  import java.util.Properties;
20  
21  import org.apache.http.HttpException;
22  import org.apache.http.HttpStatus;
23  import org.apache.http.client.methods.CloseableHttpResponse;
24  import org.apache.http.client.methods.HttpExecutionAware;
25  import org.apache.http.client.methods.HttpRequestWrapper;
26  import org.apache.http.client.protocol.HttpClientContext;
27  import org.apache.http.conn.routing.HttpRoute;
28  import org.apache.http.impl.client.cache.CachingHttpClientBuilder;
29  import org.apache.http.impl.execchain.ClientExecChain;
30  import org.esigate.HttpErrorPage;
31  import org.esigate.cache.CacheAdapter;
32  import org.esigate.events.EventManager;
33  import org.esigate.events.impl.FetchEvent;
34  
35  public class ProxyingHttpClientBuilder extends CachingHttpClientBuilder {
36      private Properties properties;
37      private EventManager eventManager;
38      private boolean useCache = true;
39  
40      @Override
41      protected ClientExecChain decorateMainExec(ClientExecChain mainExec) {
42          ClientExecChain result = mainExec;
43          result = addFetchEvent(result);
44          if (useCache) {
45              CacheAdapter cacheAdapter = new CacheAdapter();
46              cacheAdapter.init(properties);
47              result = cacheAdapter.wrapBackendHttpClient(result);
48              result = super.decorateMainExec(result);
49              result = cacheAdapter.wrapCachingHttpClient(result);
50          }
51          return result;
52      }
53  
54      public void setUseCache(boolean useCache) {
55          this.useCache = useCache;
56      }
57  
58      public void setEventManager(EventManager eventManager) {
59          this.eventManager = eventManager;
60      }
61  
62      public Properties getProperties() {
63          return properties;
64      }
65  
66      public void setProperties(Properties properties) {
67          this.properties = properties;
68      }
69  
70      public EventManager getEventManager() {
71          return eventManager;
72      }
73  
74      public boolean isUseCache() {
75          return useCache;
76      }
77  
78      /**
79       * Decorate with fetch event managements
80       * 
81       * @param wrapped
82       * @return the decorated ClientExecChain
83       */
84      private ClientExecChain addFetchEvent(final ClientExecChain wrapped) {
85          return new ClientExecChain() {
86  
87              @Override
88              public CloseableHttpResponse execute(HttpRoute route, HttpRequestWrapper request,
89                      HttpClientContext httpClientContext, HttpExecutionAware execAware) {
90                  OutgoingRequestContext context = OutgoingRequestContext.adapt(httpClientContext);
91                  // Create request event
92                  FetchEvent fetchEvent = new FetchEvent(context, request);
93  
94                  eventManager.fire(EventManager.EVENT_FETCH_PRE, fetchEvent);
95  
96                  if (fetchEvent.isExit()) {
97                      if (fetchEvent.getHttpResponse() == null) {
98                          // Provide an error page in order to avoid a NullPointerException
99                          fetchEvent.setHttpResponse(HttpErrorPage.generateHttpResponse(
100                                 HttpStatus.SC_INTERNAL_SERVER_ERROR,
101                                 "An extension stopped the processing of the request without providing a response"));
102                     }
103                 } else {
104                     try {
105                         fetchEvent.setHttpResponse(wrapped.execute(route, request, context, execAware));
106                     } catch (IOException | HttpException e) {
107                         fetchEvent.setHttpResponse(HttpErrorPage.generateHttpResponse(e));
108                     }
109                 }
110 
111                 // Update the event and fire post event
112                 eventManager.fire(EventManager.EVENT_FETCH_POST, fetchEvent);
113 
114                 return fetchEvent.getHttpResponse();
115             }
116         };
117 
118     }
119 }