|
20 | 20 |
|
21 | 21 | import static java.util.Objects.requireNonNull; |
22 | 22 |
|
23 | | -import java.io.File; |
24 | 23 | import java.net.MalformedURLException; |
25 | 24 | import java.net.URL; |
26 | | -import java.net.URLClassLoader; |
| 25 | +import java.nio.file.Files; |
| 26 | +import java.nio.file.Path; |
| 27 | +import java.nio.file.Paths; |
27 | 28 | import java.text.MessageFormat; |
28 | 29 | import java.time.Duration; |
29 | 30 | import java.util.Date; |
|
84 | 85 | */ |
85 | 86 | public class AssetHandler implements Route.Handler { |
86 | 87 |
|
87 | | - private static final Function1<ClassLoader, ClassLoader> cloader = loader().memoized(); |
| 88 | + private interface Loader { |
| 89 | + URL getResource(String name); |
| 90 | + } |
88 | 91 |
|
89 | 92 | private static final Function1<String, String> prefix = prefix().memoized(); |
90 | 93 |
|
91 | 94 | private Function2<Request, String, String> fn; |
92 | 95 |
|
93 | | - private ClassLoader loader; |
| 96 | + private Loader loader; |
94 | 97 |
|
95 | 98 | private String cdn; |
96 | 99 |
|
@@ -128,7 +131,38 @@ public class AssetHandler implements Route.Handler { |
128 | 131 | * @param loader The one who load the static resources. |
129 | 132 | */ |
130 | 133 | public AssetHandler(final String pattern, final ClassLoader loader) { |
131 | | - init(Route.normalize(pattern), loader); |
| 134 | + init(Route.normalize(pattern), Paths.get("public"), loader); |
| 135 | + } |
| 136 | + |
| 137 | + /** |
| 138 | + * <p> |
| 139 | + * Creates a new {@link AssetHandler}. The handler accepts a location pattern, that serve for |
| 140 | + * locating the static resource. |
| 141 | + * </p> |
| 142 | + * |
| 143 | + * Given <code>assets("/assets/**", "/")</code> with: |
| 144 | + * |
| 145 | + * <pre> |
| 146 | + * GET /assets/js/index.js it translates the path to: /assets/js/index.js |
| 147 | + * </pre> |
| 148 | + * |
| 149 | + * Given <code>assets("/js/**", "/assets")</code> with: |
| 150 | + * |
| 151 | + * <pre> |
| 152 | + * GET /js/index.js it translate the path to: /assets/js/index.js |
| 153 | + * </pre> |
| 154 | + * |
| 155 | + * Given <code>assets("/webjars/**", "/META-INF/resources/webjars/{0}")</code> with: |
| 156 | + * |
| 157 | + * <pre> |
| 158 | + * GET /webjars/jquery/2.1.3/jquery.js it translate the path to: /META-INF/resources/webjars/jquery/2.1.3/jquery.js |
| 159 | + * </pre> |
| 160 | + * |
| 161 | + * @param pattern Pattern to locate static resources. |
| 162 | + * @param basedir Base directory. |
| 163 | + */ |
| 164 | + public AssetHandler(final Path basedir) { |
| 165 | + init("/{0}", basedir, getClass().getClassLoader()); |
132 | 166 | } |
133 | 167 |
|
134 | 168 | /** |
@@ -158,7 +192,7 @@ public AssetHandler(final String pattern, final ClassLoader loader) { |
158 | 192 | * @param pattern Pattern to locate static resources. |
159 | 193 | */ |
160 | 194 | public AssetHandler(final String pattern) { |
161 | | - init(Route.normalize(pattern), getClass().getClassLoader()); |
| 195 | + init(Route.normalize(pattern), Paths.get("public"), getClass().getClassLoader()); |
162 | 196 | } |
163 | 197 |
|
164 | 198 | /** |
@@ -317,40 +351,34 @@ protected URL resolve(final String path) throws Exception { |
317 | 351 | return loader.getResource(path); |
318 | 352 | } |
319 | 353 |
|
320 | | - private void init(final String pattern, final ClassLoader loader) { |
| 354 | + private void init(final String pattern, final Path basedir, final ClassLoader loader) { |
321 | 355 | requireNonNull(loader, "Resource loader is required."); |
322 | 356 | this.fn = pattern.equals("/") |
323 | 357 | ? (req, p) -> prefix.apply(p) |
324 | 358 | : (req, p) -> MessageFormat.format(prefix.apply(pattern), vars(req)); |
325 | | - this.loader = cloader.apply(loader); |
| 359 | + this.loader = loader(basedir, loader); |
326 | 360 | } |
327 | 361 |
|
328 | 362 | private static Object[] vars(final Request req) { |
329 | 363 | Map<Object, String> vars = req.route().vars(); |
330 | 364 | return vars.values().toArray(new Object[vars.size()]); |
331 | 365 | } |
332 | 366 |
|
333 | | - private static Function1<ClassLoader, ClassLoader> loader() { |
334 | | - return parent -> { |
335 | | - File publicDir = new File("public"); |
336 | | - if (publicDir.exists()) { |
337 | | - try { |
338 | | - return new URLClassLoader(new URL[]{publicDir.toURI().toURL() }, null) { |
339 | | - @Override |
340 | | - public URL getResource(final String name) { |
341 | | - URL url = findResource(name); |
342 | | - if (url == null) { |
343 | | - url = parent.getResource(name); |
344 | | - } |
345 | | - return url; |
346 | | - }; |
347 | | - }; |
348 | | - } catch (MalformedURLException ex) { |
349 | | - // shh |
| 367 | + private static Loader loader(final Path basedir, final ClassLoader classloader) { |
| 368 | + if (Files.exists(basedir)) { |
| 369 | + return name -> { |
| 370 | + Path path = basedir.resolve(name).normalize(); |
| 371 | + if (Files.exists(path) && path.startsWith(basedir)) { |
| 372 | + try { |
| 373 | + return path.toUri().toURL(); |
| 374 | + } catch (MalformedURLException x) { |
| 375 | + // shh |
| 376 | + } |
350 | 377 | } |
351 | | - } |
352 | | - return parent; |
353 | | - }; |
| 378 | + return classloader.getResource(name); |
| 379 | + }; |
| 380 | + } |
| 381 | + return classloader::getResource; |
354 | 382 | } |
355 | 383 |
|
356 | 384 | private static Function1<String, String> prefix() { |
|
0 commit comments