1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.renderkit.html.util;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.myfaces.shared_tomahawk.util.ClassUtils;
24
25 import javax.servlet.ServletContext;
26 import javax.servlet.ServletOutputStream;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.text.ParseException;
32 import java.text.SimpleDateFormat;
33 import java.util.Calendar;
34 import java.util.Date;
35 import java.util.ResourceBundle;
36 import java.net.HttpURLConnection;
37
38
39
40
41
42
43
44
45
46
47
48
49 public class MyFacesResourceLoader implements ResourceLoader
50 {
51 protected static final Log log = LogFactory.getLog(MyFacesResourceLoader.class);
52
53 static final String ORG_APACHE_MYFACES_CUSTOM = "org.apache.myfaces.custom";
54
55 private static long lastModified = 0;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 private static long getLastModified()
71 {
72 if (lastModified == 0)
73 {
74 final String format = "yyyy-MM-dd HH:mm:ss Z";
75 final String bundleName = AddResource.class.getName();
76 ResourceBundle resources = ResourceBundle.getBundle(bundleName);
77 String sLastModified = resources.getString("lastModified");
78 try
79 {
80 lastModified = new SimpleDateFormat(format).parse(sLastModified).getTime();
81 }
82 catch (ParseException e)
83 {
84 lastModified = new Date().getTime();
85 log.warn("Unparsable lastModified : " + sLastModified);
86 }
87 }
88
89 return lastModified;
90 }
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 public void serveResource(ServletContext context, HttpServletRequest request,
110 HttpServletResponse response, String resourceUri) throws IOException
111 {
112 String[] uriParts = resourceUri.split("/", 2);
113
114 String component = uriParts[0];
115 if (component == null || component.trim().length() == 0)
116 {
117 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid request");
118 log.error("Could not find parameter for component to load a resource.");
119 return;
120 }
121 Class componentClass;
122 String className = ORG_APACHE_MYFACES_CUSTOM + "." + component;
123 try
124 {
125 componentClass = loadComponentClass(className);
126 }
127 catch (ClassNotFoundException e)
128 {
129 response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
130 log.error("Could not find the class for component " + className
131 + " to load a resource.");
132 return;
133 }
134 String resource = uriParts[1];
135 if (resource == null || resource.trim().length() == 0)
136 {
137 response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No resource defined");
138 log.error("No resource defined component class " + className);
139 return;
140 }
141
142 InputStream is = null;
143
144 try
145 {
146 ResourceProvider resourceProvider;
147 if (ResourceProvider.class.isAssignableFrom(componentClass))
148 {
149 try
150 {
151 resourceProvider = (ResourceProvider) componentClass.newInstance();
152 }
153 catch (InstantiationException e)
154 {
155 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Unable to instantiate resource provider for resource "
156 + resource + " for component " + component);
157 log.error("Unable to instantiate resource provider for resource " + resource + " for component " + component, e);
158 return;
159 }
160 catch (IllegalAccessException e)
161 {
162 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Unable to instantiate resource provider for resource "
163 + resource + " for component " + component);
164 log.error("Unable to instantiate resource provider for resource " + resource + " for component " + component, e);
165 return;
166 }
167 }
168 else
169 {
170 resourceProvider = new DefaultResourceProvider(componentClass);
171 }
172
173 if (!resourceProvider.exists(context, resource))
174 {
175 response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unable to find resource "
176 + resource + " for component " + component
177 + ". Check that this file is available " + "in the classpath in sub-directory "
178 + "/resource of the package-directory.");
179 log.error("Unable to find resource " + resource + " for component " + component
180 + ". Check that this file is available " + "in the classpath in sub-directory "
181 + "/resource of the package-directory.");
182 }
183 else
184 {
185
186
187 long lastModified = resourceProvider.getLastModified(context, resource);
188 if (lastModified < 1)
189 {
190
191 lastModified = getLastModified();
192 }
193
194 long browserDate = request.getDateHeader("If-Modified-Since");
195 if (browserDate > -1)
196 {
197
198 lastModified = (lastModified / 1000) * 1000;
199 browserDate = (browserDate / 1000) * 1000;
200
201 if (lastModified == browserDate)
202 {
203
204
205 response.setStatus(HttpURLConnection.HTTP_NOT_MODIFIED);
206 return;
207 }
208 }
209
210
211 int contentLength = resourceProvider.getContentLength(context, resource);
212 String contentEncoding = resourceProvider.getEncoding(context, resource);
213
214 is = resourceProvider.getInputStream(context, resource);
215
216 defineContentHeaders(request, response, resource, contentLength, contentEncoding);
217 defineCaching(request, response, resource, lastModified);
218 writeResource(request, response, is);
219 }
220 }
221 finally
222 {
223
224 }
225 }
226
227
228
229
230 protected void writeResource(HttpServletRequest request, HttpServletResponse response,
231 InputStream in) throws IOException
232 {
233 ServletOutputStream out = response.getOutputStream();
234 try
235 {
236 byte[] buffer = new byte[1024];
237 for (int size = in.read(buffer); size != -1; size = in.read(buffer))
238 {
239 out.write(buffer, 0, size);
240 }
241 out.flush();
242 }
243 catch(IOException e)
244 {
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261 log.debug("Unable to send resource data to client", e);
262 throw new ResourceLoader.ClosedSocketException();
263 }
264 }
265
266
267
268
269
270
271
272
273
274
275 protected void defineCaching(HttpServletRequest request, HttpServletResponse response,
276 String resource, long lastModified)
277 {
278 response.setDateHeader("Last-Modified", lastModified);
279
280 Calendar expires = Calendar.getInstance();
281 expires.add(Calendar.DAY_OF_YEAR, 7);
282 response.setDateHeader("Expires", expires.getTimeInMillis());
283
284
285 response.setHeader("Cache-Control", "max-age=43200");
286 response.setHeader("Pragma", "");
287 }
288
289
290
291
292
293 protected void defineContentHeaders(HttpServletRequest request, HttpServletResponse response,
294 String resource, int contentLength, String contentEncoding)
295 {
296 String charset = "";
297 if (contentEncoding != null)
298 {
299 charset = "; charset=" + contentEncoding;
300 }
301 if (contentLength > -1)
302 {
303 response.setContentLength(contentLength);
304 }
305
306 if (resource.endsWith(".js"))
307 response.setContentType(
308 org.apache.myfaces.shared_tomahawk.renderkit.html.HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT + charset);
309 else if (resource.endsWith(".css"))
310 response.setContentType(
311 org.apache.myfaces.shared_tomahawk.renderkit.html.HTML.STYLE_TYPE_TEXT_CSS + charset);
312 else if (resource.endsWith(".gif"))
313 response.setContentType("image/gif");
314 else if (resource.endsWith(".png"))
315 response.setContentType("image/png");
316 else if (resource.endsWith(".jpg") || resource.endsWith(".jpeg"))
317 response.setContentType("image/jpeg");
318 else if (resource.endsWith(".xml") || resource.endsWith(".xsl"))
319 response.setContentType("text/xml");
320 }
321
322 protected Class loadComponentClass(String componentClass) throws ClassNotFoundException
323 {
324 return ClassUtils.classForName(componentClass);
325 }
326
327
328 protected void validateCustomComponent(Class myfacesCustomComponent)
329 {
330 if (!myfacesCustomComponent.getName().startsWith(ORG_APACHE_MYFACES_CUSTOM + "."))
331 {
332 throw new IllegalArgumentException(
333 "expected a myfaces custom component class in package "
334 + ORG_APACHE_MYFACES_CUSTOM);
335 }
336 }
337 }