├── .gitignore
├── .travis.yml
├── LICENSE
├── pom.xml
├── readme.md
└── src
├── main
└── java
│ └── io
│ └── dropwizard
│ └── bundles
│ └── assets
│ ├── AssetServlet.java
│ ├── AssetsBundleConfiguration.java
│ ├── AssetsConfiguration.java
│ ├── ConfiguredAssetsBundle.java
│ └── UrlUtil.java
└── test
├── java
└── io
│ └── dropwizard
│ └── bundles
│ └── assets
│ ├── AssetServletTest.java
│ ├── AssetsBundleTest.java
│ └── AssetsConfigurationTest.java
├── more-resources
└── assets
│ └── example2.txt
└── resources
├── assets
├── config.yml
├── encoded example.txt
├── example.txt
├── foo.bar
├── foo.m4a
├── foo.mp4
├── index.htm
└── some_directory
│ ├── example.txt
│ └── index.htm
└── json
├── example.txt
└── json only.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | # IntelliJ Files
2 | .idea/
3 | *.ipr
4 | *.iws
5 | *.iml
6 |
7 | # Eclipse Files
8 | .classpath
9 | .project
10 |
11 | # Build outputs
12 | target/
13 | reports/
14 |
15 | # OS hidden files
16 | .DS_Store
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
4 | install: mvn install -Dgpg.skip
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright 2012-2015 dropwizard-bundles.io and Bazaarvoice, Inc.
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | io.dropwizard-bundles
7 | parent-pom
8 | 1.3.5
9 |
10 |
11 | dropwizard-configurable-assets-bundle
12 | 1.3.5-1-SNAPSHOT
13 | jar
14 |
15 | Dropwizard Configurable Asset Bundle
16 | An implementation of an AssetBundle for use in Dropwizard that allows user configuration.
17 |
18 |
19 |
20 | The Apache Software License, Version 2.0
21 | http://www.apache.org/licenses/LICENSE-2.0
22 | repo
23 |
24 |
25 |
26 |
27 | https://github.com/dropwizard-bundles/dropwizard-configurable-assets-bundle
28 | scm:git:https://github.com/dropwizard-bundles/dropwizard-configurable-assets-bundle
29 | scm:git:https://github.com/dropwizard-bundles/dropwizard-configurable-assets-bundle
30 | HEAD
31 |
32 |
33 |
34 |
35 | bbeck
36 | Brandon Beck
37 | http://github.com/bbeck/
38 |
39 |
40 | nbauernfeind
41 | Nate Bauernfeind
42 | http://github.com/nbauernfeind/
43 |
44 |
45 |
46 |
47 |
48 |
49 | src/test/resources
50 |
51 |
52 | src/test/more-resources
53 |
54 |
55 |
56 |
57 |
58 |
59 | io.dropwizard
60 | dropwizard-core
61 |
62 |
63 | io.dropwizard
64 | dropwizard-servlets
65 |
66 |
67 | junit
68 | junit
69 | test
70 |
71 |
72 | org.assertj
73 | assertj-core
74 | 1.7.1
75 | test
76 |
77 |
78 | org.eclipse.jetty
79 | jetty-http
80 | tests
81 | test
82 |
83 |
84 | org.eclipse.jetty
85 | jetty-servlet
86 | test
87 |
88 |
89 | org.eclipse.jetty
90 | jetty-servlet
91 | tests
92 | test
93 |
94 |
95 | org.mockito
96 | mockito-core
97 | test
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Configurable Assets Bundle for Dropwizard
2 |
3 | This GitHub repository contains a drop-in replacement for Yammer's `AssetsBundle` class that allows
4 | for a better developer experience. Developers can use the `ConfiguredAssetsBundle` class anywhere
5 | they would use a `AssetsBundle` in their Dropwizard applications and take advantage of the ability
6 | to specify redirects for URIs to that loads them from disk instead of the classpath. This allows
7 | developers to edit browser-interpreted files and reload them without needing to recompile source.
8 |
9 | [](https://travis-ci.org/dropwizard-bundles/dropwizard-configurable-assets-bundle)
10 |
11 | ## Maven Setup
12 |
13 | ```xml
14 |
15 | io.dropwizard-bundles
16 | dropwizard-configurable-assets-bundle
17 | 1.0.5
18 |
19 | ```
20 |
21 | ## Getting Started
22 |
23 | Implement the AssetsBundleConfiguration:
24 | ```java
25 | public class SampleConfiguration extends Configuration implements AssetsBundleConfiguration {
26 | @Valid
27 | @NotNull
28 | @JsonProperty
29 | private final AssetsConfiguration assets = AssetsConfiguration.builder().build();
30 |
31 | @Override
32 | public AssetsConfiguration getAssetsConfiguration() {
33 | return assets;
34 | }
35 | }
36 | ```
37 |
38 | Add the assets bundle:
39 | ```java
40 | public class SampleService extends Application {
41 | public static void main(String[] args) throws Exception {
42 | new SampleService().run(args);
43 | }
44 |
45 | @Override
46 | public void initialize(Bootstrap bootstrap) {
47 | // Map requests to /dashboard/${1} to be found in the class path at /assets/${1}.
48 | bootstrap.addBundle(new ConfiguredAssetsBundle("/assets/", "/dashboard/"));
49 | }
50 |
51 | @Override
52 | public void run(SampleConfiguration configuration, Environment environment) {
53 | ...
54 | }
55 | }
56 | ```
57 |
58 | A sample local development config:
59 | ```yml
60 | assets:
61 | overrides:
62 | # Override requests to /dashboard/${1} to instead look in
63 | # ${working directory}/src/main/resources/assets/${1}
64 | /dashboard: src/main/resources/assets/
65 | ```
66 |
67 | You can override multiple external folders with a single configuration in a following way:
68 | ```yml
69 | assets:
70 | overrides:
71 | /dashboard/assets: /some/absolute/path/with/assets/
72 | /dashboard/images: /some/different/absolute/path/with/images
73 | ```
74 |
75 | Instead of defining the resource path to uri path mappings in java code, they also can be specified in the configuration file.
76 | ```java
77 | public class SampleService extends Application {
78 | ...
79 |
80 | @Override
81 | public void initialize(Bootstrap bootstrap) {
82 | bootstrap.addBundle(new ConfiguredAssetsBundle());
83 | }
84 |
85 | @Override
86 | public void run(SampleConfiguration configuration, Environment environment) {
87 | ...
88 | }
89 | }
90 | ```
91 |
92 | ```yml
93 | assets:
94 | mappings:
95 | /assets: /dashboard
96 | overrides:
97 | /dashboard/assets: /some/absolute/path/with/assets/
98 | /dashboard/images: /some/different/absolute/path/with/images
99 | ```
100 |
101 | ## Add Mime Types
102 |
103 | Since 0.8, Dropwizard allows you to add new mimetypes directly to the application context.
104 |
105 | ```java
106 | public class SampleService extends Application {
107 | ...
108 |
109 | @Override
110 | public void run(SampleConfiguration configuration, Environment environment) {
111 | environment
112 | .getApplicationContext()
113 | .getMimeTypes()
114 | .addMimeMapping("mp4", "video/mp4");
115 | }
116 | }
117 | ```
118 |
119 | However if you want to override a pre-existing mime type, or add them dynamically, you can do so
120 | with your assets configuration.
121 |
122 | ```yml
123 | assets:
124 | mimeTypes:
125 | woff: application/font-woff
126 | ```
127 |
128 | ## Multiple URI Mappings
129 |
130 | You can map different folders to multiple top-level directories if you wish.
131 |
132 | Either in java code
133 | ```java
134 | public class SampleService extends Application {
135 | ...
136 |
137 | @Override
138 | public void initialize(Bootstrap bootstrap) {
139 | bootstrap.addBundle(new ConfiguredAssetsBundle(
140 | ImmutableMap.builder()
141 | .put("/assets/", "/dashboard/")
142 | .put("/data/", "/static-data/")
143 | .build()
144 | ));
145 | }
146 | }
147 | ```
148 |
149 | or either in the configuration file
150 | ```yml
151 | assets:
152 | mappings:
153 | /assets: /dashboard
154 | /data: /static-data
155 | overrides:
156 | ...
157 | ```
158 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/bundles/assets/AssetServlet.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.bundles.assets;
2 |
3 | import com.google.common.base.CharMatcher;
4 | import com.google.common.base.Joiner;
5 | import com.google.common.base.Splitter;
6 | import com.google.common.cache.CacheBuilder;
7 | import com.google.common.cache.CacheBuilderSpec;
8 | import com.google.common.cache.CacheLoader;
9 | import com.google.common.cache.LoadingCache;
10 | import com.google.common.cache.Weigher;
11 | import com.google.common.collect.ImmutableList;
12 | import com.google.common.collect.Maps;
13 | import com.google.common.hash.Hashing;
14 | import com.google.common.io.Files;
15 | import com.google.common.io.Resources;
16 | import com.google.common.net.HttpHeaders;
17 | import com.google.common.net.MediaType;
18 | import io.dropwizard.servlets.assets.ByteRange;
19 | import io.dropwizard.servlets.assets.ResourceURL;
20 | import java.io.File;
21 | import java.io.IOException;
22 | import java.net.URL;
23 | import java.nio.charset.Charset;
24 | import java.util.List;
25 | import java.util.Map;
26 | import javax.servlet.ServletException;
27 | import javax.servlet.ServletOutputStream;
28 | import javax.servlet.http.HttpServlet;
29 | import javax.servlet.http.HttpServletRequest;
30 | import javax.servlet.http.HttpServletResponse;
31 | import org.eclipse.jetty.http.MimeTypes;
32 |
33 | /**
34 | * Servlet responsible for serving assets to the caller. This is basically completely stolen from
35 | * {@link io.dropwizard.servlets.assets.AssetServlet} with the exception of allowing for override
36 | * options.
37 | *
38 | * @see io.dropwizard.servlets.assets.AssetServlet
39 | */
40 | public class AssetServlet extends HttpServlet {
41 | private static final long serialVersionUID = 6393345594784987908L;
42 | private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.HTML_UTF_8;
43 | private static final CharMatcher SLASHES = CharMatcher.is('/');
44 |
45 | private final transient CacheBuilderSpec cacheSpec;
46 | private final transient LoadingCache cache;
47 | private final transient MimeTypes mimeTypes;
48 |
49 | private Charset defaultCharset;
50 |
51 | private String cacheControlHeader = null;
52 |
53 | /**
54 | * Creates a new {@code AssetServlet} that serves static assets loaded from {@code resourceURL}
55 | * (typically a file: or jar: URL). The assets are served at URIs rooted at {@code uriPath}. For
56 | * example, given a {@code resourceURL} of {@code "file:/data/assets"} and a {@code uriPath} of
57 | * {@code "/js"}, an {@code AssetServlet} would serve the contents of {@code
58 | * /data/assets/example.js} in response to a request for {@code /js/example.js}. If a directory
59 | * is requested and {@code indexFile} is defined, then {@code AssetServlet} will attempt to
60 | * serve a file with that name in that directory. If a directory is requested and {@code
61 | * indexFile} is null, it will serve a 404.
62 | *
63 | * @param resourcePathToUriPathMapping A mapping from base URL's from which assets are loaded to
64 | * the URI path fragment in which the requests for that asset
65 | * are rooted
66 | * @param indexFile the filename to use when directories are requested, or null
67 | * to serve no indexes
68 | * @param defaultCharset the default character set
69 | * @param spec the CacheBuilderSpec to use
70 | * @param overrides the path overrides
71 | * @param mimeTypes the mimeType overrides
72 | */
73 | public AssetServlet(Iterable> resourcePathToUriPathMapping,
74 | String indexFile,
75 | Charset defaultCharset,
76 | CacheBuilderSpec spec,
77 | Iterable> overrides,
78 | Iterable> mimeTypes) {
79 | this.defaultCharset = defaultCharset;
80 | AssetLoader loader = new AssetLoader(resourcePathToUriPathMapping, indexFile, overrides);
81 |
82 | CacheBuilder