View Javadoc
1   package de.juplo.httpresources;
2   
3   
4   import java.time.Clock;
5   import org.slf4j.Logger;
6   import org.slf4j.LoggerFactory;
7   import org.springframework.boot.autoconfigure.AutoConfigureBefore;
8   import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
9   import org.springframework.boot.autoconfigure.web.ResourceProperties;
10  import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
11  import org.springframework.boot.context.properties.EnableConfigurationProperties;
12  import org.springframework.cache.Cache;
13  import org.springframework.cache.concurrent.ConcurrentMapCache;
14  import org.springframework.cache.support.NoOpCache;
15  import org.springframework.context.ApplicationContext;
16  import org.springframework.context.annotation.Bean;
17  import org.springframework.context.annotation.Configuration;
18  import org.springframework.core.io.DefaultResourceLoader;
19  import org.springframework.http.client.ClientHttpRequestFactory;
20  
21  
22  /**
23   * Automatic configuration
24   *
25   * @author Kai Moritz
26   */
27  @Configuration
28  @EnableConfigurationProperties(HttpResourcesProperties.class)
29  @AutoConfigureBefore(WebMvcAutoConfiguration.class)
30  public class HttpResourcesAutoConfiguration
31  {
32    private static final Logger LOG =
33        LoggerFactory.getLogger(HttpResourcesAutoConfiguration.class);
34  
35    public static final String CACHE_NAME = "http-resources-cache";
36  
37  
38    @ConditionalOnMissingBean(Clock.class)
39    @Bean
40    public Clock clock()
41    {
42      return Clock.systemDefaultZone();
43    }
44  
45    @ConditionalOnMissingBean(name = "sources")
46    @Bean
47    public String[] sources(ResourceProperties properties)
48    {
49      String[] sources = properties.getStaticLocations();
50  
51      if (sources.length == 0)
52        throw new IllegalArgumentException("At least one source must be configured!");
53  
54      boolean hasRemoteResource = false;
55      for (String source : sources)
56        hasRemoteResource |= HttpResources.isHttpResource(source);
57      if (!hasRemoteResource)
58        LOG.warn("No remote-resource in {}", sources);
59  
60      return sources;
61    }
62  
63  
64    @ConditionalOnMissingBean(HttpResourceFetcher.class)
65    @Bean
66    public HttpResourceFetcher fetcher(
67        ClientHttpRequestFactory requestFactory,
68        Clock clock,
69        HttpResourcesProperties properties)
70    {
71      LOG.info(
72          "Creating bean of type HttpResourceFetcher (default-ttl={}, min-ttl={}, serve-stale={})",
73          properties.defaultTTL,
74          properties.minTTL,
75          properties.serveStale);
76  
77      Cache cache;
78      if (properties.cache)
79      {
80        LOG.info("Enable caching for HttpResources");
81        cache = new ConcurrentMapCache(CACHE_NAME);
82      }
83      else
84      {
85        cache = new NoOpCache(CACHE_NAME);
86      }
87  
88      return new HttpResourceFetcher(
89          requestFactory,
90          cache,
91          clock,
92          properties.defaultTTL,
93          properties.minTTL,
94          properties.serveStale);
95    }
96  
97    @ConditionalOnMissingBean(HttpResources.class)
98    @Bean
99    public HttpResources httpResources(
100       HttpResourceFetcher fetcher,
101       Clock clock,
102       HttpResourcesProperties properties
103       )
104   {
105     LOG.info(
106         "Creating bean of type HttpResources (fetcher={}, cache={})",
107         properties.cache,
108         fetcher);
109 
110     HttpResources#HttpResources">HttpResources resources = new HttpResources(fetcher, clock);
111     return resources;
112   }
113 
114   @ConditionalOnMissingBean
115   @Bean
116   public HttpResourceProtocolResolver httpResourceProtocolResolver(
117       HttpResources resources,
118       HttpResourcesProperties properties,
119       DefaultResourceLoader resourceLoader
120       )
121   {
122     LOG.info("Creating and registrating a bean of type HttpResourceProtocolResolver");
123     HttpResourceProtocolResolver resolver =
124         new HttpResourceProtocolResolver(resources);
125     resourceLoader.addProtocolResolver(resolver);
126     return resolver;
127   }
128 
129   @ConditionalOnMissingBean
130   @Bean
131   public HttpResourceChainAwareResourceLoader httpResourceChainAwareResourceLoader(
132       ApplicationContext context,
133       String[] sources
134       )
135   {
136     LOG.info("Creating a bean of type HttpResourceChainAwareResourceLoader");
137     return new HttpResourceChainAwareResourceLoader(context, sources);
138   }
139 }