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 InputStream in = null;
204
205 for (String path : paths) {
206 try {
207 if (!path.startsWith(resourcesRoot)) {
208 path = resourcesRoot + path;
209 }
210 in = ClasspathResourcesUtil.getStream(path);
211 if (in != null) {
212 IOUtils.copy(in, out);
213 }
214 } finally {
215 IOUtils.closeQuietly(in);
216 }
217 }
218
219 out.flush();
220 IOUtils.closeQuietly(out);
221 }
222
223 private void streamSingleFile(HttpServletResponse response, String filePath) throws IOException {
224 InputStream in = null;
225
226
227 try {
228 in = ClasspathResourcesUtil.getStream(resourcesRoot + filePath);
229 } catch (IOException e) {
230 IOUtils.closeQuietly(in);
231 }
232
233 if (in == null) {
234 if (!response.isCommitted()) {
235 response.sendError(HttpServletResponse.SC_NOT_FOUND);
236 }
237 return;
238 }
239
240 ServletOutputStream out = null;
241 try {
242 out = response.getOutputStream();
243 IOUtils.copy(in, out);
244 out.flush();
245 } catch (IOException e) {
246
247
248 log.debug("Unable to spool resource due to a {} exception", e.getClass().getName());
249 if (!response.isCommitted()) {
250 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
251 }
252 } finally {
253 IOUtils.closeQuietly(out);
254 IOUtils.closeQuietly(in);
255 }
256 }
257
258 }