1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.springframework.extensions.webscripts.servlet.mvc;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.net.URL;
25 import java.net.URLConnection;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import javax.servlet.RequestDispatcher;
30 import javax.servlet.ServletException;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.springframework.core.io.Resource;
37 import org.springframework.util.ClassUtils;
38 import org.springframework.web.context.support.ServletContextResource;
39 import org.springframework.web.servlet.HandlerMapping;
40 import org.springframework.web.servlet.ModelAndView;
41 import org.springframework.web.servlet.mvc.AbstractController;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class ResourceController extends AbstractController
60 {
61 private static Log logger = LogFactory.getLog(ResourceController.class);
62
63 private static final String HTTP_CONTENT_LENGTH_HEADER = "Content-Length";
64 private static final String HTTP_LAST_MODIFIED_HEADER = "Last-Modified";
65 private static final String HTTP_EXPIRES_HEADER = "Expires";
66 private static final String HTTP_CACHE_CONTROL_HEADER = "Cache-Control";
67
68 private static int BUFFER_SIZE = 1024;
69
70 private Map<String, String> defaultMimeTypes = new HashMap<String, String>();
71 {
72 defaultMimeTypes.put(".css", "text/css");
73 defaultMimeTypes.put(".gif", "image/gif");
74 defaultMimeTypes.put(".ico", "image/vnd.microsoft.icon");
75 defaultMimeTypes.put(".jpeg", "image/jpeg");
76 defaultMimeTypes.put(".jpg", "image/jpeg");
77 defaultMimeTypes.put(".js", "text/javascript");
78 defaultMimeTypes.put(".png", "image/png");
79 }
80
81
82 private String defaultUrl;
83
84
85
86
87
88
89 public void setDefaultUrl(String defaultUrl)
90 {
91 this.defaultUrl = defaultUrl;
92 }
93
94
95
96
97
98
99 public String getDefaultUrl()
100 {
101 return this.defaultUrl;
102 }
103
104
105
106
107 public Log getLogger()
108 {
109 return logger;
110 }
111
112
113
114
115 public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
116 throws Exception
117 {
118
119 String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
120
121 dispatchResource(path, request, response);
122
123 return null;
124 }
125
126
127
128
129
130
131
132
133
134
135 public boolean dispatchResource(String path, HttpServletRequest request, HttpServletResponse response)
136 throws ServletException, IOException
137 {
138 boolean resolved = false;
139
140
141 ServletContextResource resource = new ServletContextResource(getServletContext(), "/" + path);
142 if (resource.exists())
143 {
144
145 RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/" + path);
146 rd.include(request, response);
147
148 resolved = true;
149 }
150
151 if (!resolved)
152 {
153
154
155
156
157 Resource r = getApplicationContext().getResource("classpath*:" + path);
158 if (r != null && r.exists())
159 {
160 URL resourceUrl = r.getURL();
161
162
163 try
164 {
165 commitResponse(resourceUrl, response);
166 resolved = true;
167 }
168 catch (IOException ioe)
169 {
170 ioe.printStackTrace();
171 }
172 }
173 }
174
175 if (!resolved)
176 {
177
178 URL resourceUrl = ClassUtils.getDefaultClassLoader().getResource("META-INF/" + path);
179 if (resourceUrl != null)
180 {
181
182 try
183 {
184 commitResponse(resourceUrl, response);
185 resolved = true;
186 }
187 catch (IOException ioe)
188 {
189 ioe.printStackTrace();
190
191 }
192 }
193 }
194
195 if (!resolved && defaultUrl != null)
196 {
197
198
199 RequestDispatcher rd = this.getServletContext().getRequestDispatcher(defaultUrl + "/" + path);
200 rd.forward(request, response);
201
202 resolved = true;
203 }
204
205 return resolved;
206 }
207
208 public void commitResponse(URL resourceUrl, HttpServletResponse response)
209 throws IOException
210 {
211 long lastModified = -1;
212
213
214 URLConnection resourceConn = resourceUrl.openConnection();
215 if (resourceConn.getLastModified() > lastModified)
216 {
217 lastModified = resourceConn.getLastModified();
218 }
219 String mimetype = getServletContext().getMimeType(resourceUrl.getPath());
220 if (mimetype == null)
221 {
222 String extension = resourceUrl.getPath().substring(resourceUrl.getPath().lastIndexOf('.'));
223 mimetype = (String) defaultMimeTypes.get(extension);
224 }
225 int contentLength = resourceConn.getContentLength();
226
227
228 response.setContentType(mimetype);
229 response.setHeader(HTTP_CONTENT_LENGTH_HEADER, Long.toString(contentLength));
230 response.setDateHeader(HTTP_LAST_MODIFIED_HEADER, lastModified);
231
232
233 copyStream(resourceUrl.openStream(), response.getOutputStream(), true);
234 }
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251 public static int copyStream(final InputStream in, final OutputStream out, final boolean closeStreams)
252 throws IOException
253 {
254 try
255 {
256 int byteCount = 0;
257 final byte[] buffer = new byte[BUFFER_SIZE];
258 int bytesRead = -1;
259 while ((bytesRead = in.read(buffer)) != -1)
260 {
261 out.write(buffer, 0, bytesRead);
262 byteCount += bytesRead;
263 }
264 out.flush();
265 return byteCount;
266 }
267 finally
268 {
269 if (closeStreams)
270 {
271 try
272 {
273 in.close();
274 }
275 catch (IOException ex)
276 {
277 }
278 try
279 {
280 out.close();
281 }
282 catch (IOException ex)
283 {
284 }
285 }
286 }
287 }
288
289 }