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.lang.StringUtils;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59
60
61
62
63
64
65
66
67 public class ClasspathSpool extends HttpServlet {
68
69
70
71
72 public static final String MGNL_RESOURCES_ROOT = "/mgnl-resources";
73
74 private static final long serialVersionUID = 222L;
75
76 private final static Logger log = LoggerFactory.getLogger(ClasspathSpool.class);
77
78 protected long getLastModified(HttpServletRequest req) {
79 String filePath = this.getFilePath(req);
80 try {
81 URL url = ClasspathResourcesUtil.getResource(MGNL_RESOURCES_ROOT + 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 }
93 finally{
94 IOUtils.closeQuietly(is);
95 }
96 return lastModified;
97 }
98 }
99 catch (IOException e) {
100
101 }
102
103 return -1;
104 }
105
106
107
108
109
110 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
111
112 String filePath = getFilePath(request);
113
114 if (StringUtils.contains(filePath, "*")) {
115 streamMultipleFile(response, filePath);
116 }
117 else if (StringUtils.contains(filePath, "|")) {
118 String[] paths = StringUtils.split(filePath, "|");
119 streamMultipleFile(response, paths);
120 }
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 public void init() throws ServletException {
148 super.init();
149 multipleFilePathsCache = new Hashtable<String, String[]>();
150 }
151
152
153
154
155 public void destroy() {
156 super.destroy();
157 multipleFilePathsCache.clear();
158 }
159
160
161
162
163
164 private void streamMultipleFile(HttpServletResponse response, String filePath) throws IOException {
165 if (log.isDebugEnabled()) {
166 log.debug("aggregating files for request {}", filePath);
167 }
168
169 String[] paths = multipleFilePathsCache.get(filePath);
170 if (paths == null) {
171 final String startsWith = MGNL_RESOURCES_ROOT + StringUtils.substringBefore(filePath, "*");
172 final String endssWith = StringUtils.substringAfterLast(filePath, "*");
173
174 paths = ClasspathResourcesUtil.findResources(new ClasspathResourcesUtil.Filter() {
175
176 public boolean accept(String name) {
177 return name.startsWith(startsWith) && name.endsWith(endssWith);
178 }
179 });
180 }
181 multipleFilePathsCache.put(filePath, paths);
182
183 if (paths.length == 0) {
184 response.sendError(HttpServletResponse.SC_NOT_FOUND);
185 return;
186 }
187
188 streamMultipleFile(response, paths);
189 }
190
191 private void streamMultipleFile(HttpServletResponse response, String[] paths) throws IOException {
192 ServletOutputStream out = response.getOutputStream();
193 InputStream in = null;
194
195 for (String path : paths) {
196 try {
197 if (!path.startsWith(MGNL_RESOURCES_ROOT)) {
198 path = MGNL_RESOURCES_ROOT + path;
199 }
200 in = ClasspathResourcesUtil.getStream(path);
201 if (in != null) {
202 IOUtils.copy(in, out);
203 }
204 }
205 finally {
206 IOUtils.closeQuietly(in);
207 }
208 }
209
210 out.flush();
211 IOUtils.closeQuietly(out);
212 }
213
214 private void streamSingleFile(HttpServletResponse response, String filePath) throws IOException {
215 InputStream in = null;
216
217
218 try {
219 in = ClasspathResourcesUtil.getStream(MGNL_RESOURCES_ROOT + filePath);
220 }
221 catch (IOException e) {
222 IOUtils.closeQuietly(in);
223 }
224
225 if (in == null) {
226 if (!response.isCommitted()) {
227 response.sendError(HttpServletResponse.SC_NOT_FOUND);
228 }
229 return;
230 }
231
232 try {
233 ServletOutputStream out = response.getOutputStream();
234 IOUtils.copy(in, out);
235 out.flush();
236 IOUtils.closeQuietly(out);
237 }
238 catch (IOException e) {
239
240
241 log.debug("Unable to spool resource due to a {} exception", e.getClass().getName());
242 if (!response.isCommitted()) {
243 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
244 }
245 }
246 finally {
247 IOUtils.closeQuietly(in);
248 }
249 }
250
251 }