1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.servlets;
35
36 import info.magnolia.cms.util.ClasspathResourcesUtil;
37
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.net.URL;
41 import java.net.URLConnection;
42 import java.util.Hashtable;
43 import java.util.Map;
44
45 import javax.servlet.ServletException;
46 import javax.servlet.ServletOutputStream;
47 import javax.servlet.http.HttpServlet;
48 import javax.servlet.http.HttpServletRequest;
49 import javax.servlet.http.HttpServletResponse;
50
51 import org.apache.commons.io.IOUtils;
52 import org.apache.commons.lang3.StringUtils;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59
60
61
62
63
64
65 @Deprecated
66 public class ClasspathSpool extends HttpServlet {
67
68
69
70
71 public static final String MGNL_DEFAULT_RESOURCES_ROOT = "/mgnl-resources";
72
73 private final static Logger log = LoggerFactory.getLogger(ClasspathSpool.class);
74
75 private String resourcesRoot;
76
77 @Override
78 protected long getLastModified(HttpServletRequest req) {
79 String filePath = this.getFilePath(req);
80 try {
81 URL url = ClasspathResourcesUtil.getResource(resourcesRoot + filePath);
82 if (url != null) {
83 URLConnection connection = url.openConnection();
84
85 connection.setDoInput(false);
86 connection.setDoOutput(false);
87
88 long lastModified = connection.getLastModified();
89 InputStream is = null;
90 try {
91 is = connection.getInputStream();
92 } finally {
93 IOUtils.closeQuietly(is);
94 }
95 return lastModified;
96 }
97 } catch (IOException e) {
98
99 }
100
101 return -1;
102 }
103
104
105
106
107
108
109 @Override
110 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
111
112 String filePath = getFilePath(request);
113
114 log.warn("ClasspathSpool servlet is used for {}. The servlet is deprecated and will be removed in a future release. Please use info.magnolia.module.resources.servlets.ResourcesServlet instead.", filePath);
115
116 if (StringUtils.contains(filePath, "*")) {
117 streamMultipleFile(response, filePath);
118 } else if (StringUtils.contains(filePath, "|")) {
119 String[] paths = StringUtils.split(filePath, "|");
120 streamMultipleFile(response, paths);
121 } else {
122 streamSingleFile(response, filePath);
123 }
124 }
125
126 protected String getFilePath(HttpServletRequest request) {
127
128 String filePath = (String) request.getAttribute("javax.servlet.include.path_info");
129
130
131 if (StringUtils.isEmpty(filePath)) {
132 filePath = (String) request.getAttribute("javax.servlet.forward.path_info");
133 }
134
135
136 if (StringUtils.isEmpty(filePath)) {
137 filePath = request.getPathInfo();
138 }
139 return filePath;
140 }
141
142 private Map<String, String[]> multipleFilePathsCache;
143
144
145
146
147 @Override
148 public void init() throws ServletException {
149 super.init();
150 multipleFilePathsCache = new Hashtable<String, String[]>();
151 resourcesRoot = StringUtils.defaultIfEmpty(getInitParameter("resourcesRoot"), MGNL_DEFAULT_RESOURCES_ROOT);
152
153 URL url = ClasspathResourcesUtil.getResource(resourcesRoot);
154 log.debug("resources root is {}", resourcesRoot);
155 if (url == null) {
156 log.warn("Resource classpath root {} does not seem to exist. Some resources might not be available, please check your configuration. Falling back to default resources root {}", resourcesRoot, MGNL_DEFAULT_RESOURCES_ROOT);
157
158 resourcesRoot = MGNL_DEFAULT_RESOURCES_ROOT;
159 }
160 }
161
162
163
164
165 @Override
166 public void destroy() {
167 super.destroy();
168 multipleFilePathsCache.clear();
169 }
170
171
172
173
174
175 private void streamMultipleFile(HttpServletResponse response, String filePath) throws IOException {
176 log.debug("aggregating files for request {}", filePath);
177
178 String[] paths = multipleFilePathsCache.get(filePath);
179 if (paths == null) {
180 final String startsWith = resourcesRoot + StringUtils.substringBefore(filePath, "*");
181 final String endsWith = StringUtils.substringAfterLast(filePath, "*");
182
183 paths = ClasspathResourcesUtil.findResources(new ClasspathResourcesUtil.Filter() {
184
185 @Override
186 public boolean accept(String name) {
187 return name.startsWith(startsWith) && name.endsWith(endsWith);
188 }
189 });
190 }
191 multipleFilePathsCache.put(filePath, paths);
192
193 if (paths.length == 0) {
194 response.sendError(HttpServletResponse.SC_NOT_FOUND);
195 return;
196 }
197
198 streamMultipleFile(response, paths);
199 }
200
201 private void streamMultipleFile(HttpServletResponse response, String[] paths) throws IOException {
202 ServletOutputStream out = response.getOutputStream();
203 try {
204 InputStream in = null;
205
206 for (String path : paths) {
207 try {
208 if (!path.startsWith(resourcesRoot)) {
209 path = resourcesRoot + path;
210 }
211 in = ClasspathResourcesUtil.getStream(path);
212 if (in != null) {
213 IOUtils.copy(in, out);
214 }
215 } finally {
216 IOUtils.closeQuietly(in);
217 }
218 }
219 } finally {
220 out.flush();
221 IOUtils.closeQuietly(out);
222 }
223 }
224
225 private void streamSingleFile(HttpServletResponse response, String filePath) throws IOException {
226 InputStream in = null;
227
228
229 try {
230 in = ClasspathResourcesUtil.getStream(resourcesRoot + filePath);
231 } catch (IOException e) {
232 IOUtils.closeQuietly(in);
233 }
234
235 if (in == null) {
236 if (!response.isCommitted()) {
237 response.sendError(HttpServletResponse.SC_NOT_FOUND);
238 }
239 return;
240 }
241
242 ServletOutputStream out = null;
243 try {
244 out = response.getOutputStream();
245 IOUtils.copy(in, out);
246 out.flush();
247 } catch (IOException e) {
248
249
250 log.debug("Unable to spool resource due to a {} exception", e.getClass().getName());
251 if (!response.isCommitted()) {
252 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
253 }
254 } finally {
255 IOUtils.closeQuietly(out);
256 IOUtils.closeQuietly(in);
257 }
258 }
259
260 }