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
24
25
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 }