1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.impl;
20
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.lang.reflect.Method;
24 import java.net.URL;
25 import java.net.URLConnection;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30 import java.util.regex.Pattern;
31
32 import javax.el.ELException;
33 import javax.faces.FacesException;
34 import javax.faces.FactoryFinder;
35 import javax.faces.view.facelets.FaceletCache;
36 import javax.faces.view.facelets.FaceletCacheFactory;
37 import javax.faces.view.facelets.FaceletException;
38 import javax.faces.view.facelets.FaceletHandler;
39 import javax.faces.view.facelets.ResourceResolver;
40
41 import org.apache.myfaces.shared.resource.ResourceLoaderUtils;
42 import org.apache.myfaces.view.facelets.Facelet;
43 import org.apache.myfaces.view.facelets.FaceletFactory;
44 import org.apache.myfaces.view.facelets.compiler.Compiler;
45 import org.apache.myfaces.view.facelets.util.ParameterCheck;
46
47
48
49
50
51
52
53 public final class DefaultFaceletFactory extends FaceletFactory
54 {
55 private static final long INFINITE_DELAY = -1;
56 private static final long NO_CACHE_DELAY = 0;
57
58
59 protected final Logger log = Logger.getLogger(DefaultFaceletFactory.class.getName());
60
61 private URL _baseUrl;
62
63 private Compiler _compiler;
64
65
66
67
68
69 private Map<String, DefaultFacelet> _compositeComponentMetadataFacelets;
70
71 private long _refreshPeriod;
72
73 private Map<String, URL> _relativeLocations;
74
75 private javax.faces.view.facelets.ResourceResolver _resolver;
76
77 private FaceletCache<Facelet> _faceletCache;
78
79 public DefaultFaceletFactory(Compiler compiler, ResourceResolver resolver) throws IOException
80 {
81 this(compiler, resolver, -1);
82 }
83
84 public DefaultFaceletFactory(Compiler compiler, ResourceResolver resolver, long refreshPeriod)
85 {
86 ParameterCheck.notNull("compiler", compiler);
87 ParameterCheck.notNull("resolver", resolver);
88
89 _compiler = compiler;
90
91
92
93
94
95 _compositeComponentMetadataFacelets = new HashMap<String, DefaultFacelet>();
96
97 _relativeLocations = new HashMap<String, URL>();
98
99 _resolver = resolver;
100
101 _baseUrl = resolver.resolveUrl("/");
102
103 _refreshPeriod = refreshPeriod < 0 ? INFINITE_DELAY : refreshPeriod * 1000;
104
105
106 FaceletCacheFactory cacheFactory
107 = (FaceletCacheFactory) FactoryFinder.getFactory(FactoryFinder.FACELET_CACHE_FACTORY);
108 _faceletCache = (FaceletCache<Facelet>) cacheFactory.getFaceletCache();
109
110 FaceletCache.MemberFactory<Facelet> faceletFactory = new FaceletCache.MemberFactory<Facelet>()
111 {
112 public Facelet newInstance(URL url) throws IOException
113 {
114 return _createFacelet(url);
115 }
116 };
117 FaceletCache.MemberFactory<Facelet> viewMetadataFaceletFactory = new FaceletCache.MemberFactory<Facelet>()
118 {
119 public Facelet newInstance(URL url) throws IOException
120 {
121 return _createViewMetadataFacelet(url);
122 }
123 };
124
125
126
127
128
129
130 try
131 {
132 Method setMemberFactoriesMethod = FaceletCache.class.getDeclaredMethod("setMemberFactories",
133 new Class[]{FaceletCache.MemberFactory.class, FaceletCache.MemberFactory.class});
134 setMemberFactoriesMethod.setAccessible(true);
135 setMemberFactoriesMethod.invoke(_faceletCache, faceletFactory, viewMetadataFaceletFactory);
136 }
137 catch (Exception e)
138 {
139 throw new FacesException("Cannot call setMemberFactories method, Initialization of FaceletCache failed.",
140 e);
141 }
142
143 if (log.isLoggable(Level.FINE))
144 {
145 log.fine("Using ResourceResolver: " + _resolver);
146 log.fine("Using Refresh Period: " + _refreshPeriod);
147 }
148 }
149
150
151
152
153
154
155 public Compiler getCompiler()
156 {
157 return _compiler;
158 }
159
160
161
162
163
164
165 public Facelet getFacelet(String uri) throws IOException, FaceletException, FacesException, ELException
166 {
167 URL url = (URL) _relativeLocations.get(uri);
168 if (url == null)
169 {
170 url = resolveURL(_baseUrl, uri);
171 if (url != null)
172 {
173 Map<String, URL> newLoc = new HashMap<String, URL>(_relativeLocations);
174 newLoc.put(uri, url);
175 _relativeLocations = newLoc;
176 }
177 else
178 {
179 throw new IOException("'" + uri + "' not found.");
180 }
181 }
182 return this.getFacelet(url);
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196
197 public Facelet getFacelet(URL url) throws IOException, FaceletException, FacesException, ELException
198 {
199 return _faceletCache.getFacelet(url);
200 }
201
202 public long getRefreshPeriod()
203 {
204 return _refreshPeriod;
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 public URL resolveURL(URL source, String path) throws IOException
221 {
222 if (path.startsWith("/"))
223 {
224 URL url = _resolver.resolveUrl(path);
225 if (url == null)
226 {
227 throw new FileNotFoundException(path + " Not Found in ExternalContext as a Resource");
228 }
229 return url;
230 }
231 else
232 {
233 return new URL(source, path);
234 }
235 }
236
237
238
239
240
241
242
243
244 protected boolean needsToBeRefreshed(DefaultFacelet facelet)
245 {
246
247 if (_refreshPeriod == NO_CACHE_DELAY)
248 {
249 return true;
250 }
251
252
253 if (_refreshPeriod == INFINITE_DELAY)
254 {
255 return false;
256 }
257
258 long target = facelet.getCreateTime() + _refreshPeriod;
259 if (System.currentTimeMillis() > target)
260 {
261
262
263 try
264 {
265 URLConnection conn = facelet.getSource().openConnection();
266 long lastModified = ResourceLoaderUtils.getResourceLastModified(conn);
267
268 return lastModified == 0 || lastModified > target;
269 }
270 catch (IOException e)
271 {
272 throw new FaceletException("Error Checking Last Modified for " + facelet.getAlias(), e);
273 }
274 }
275
276 return false;
277 }
278
279
280
281
282
283
284
285
286
287
288
289
290 private DefaultFacelet _createFacelet(URL url) throws IOException, FaceletException, FacesException, ELException
291 {
292 if (log.isLoggable(Level.FINE))
293 {
294 log.fine("Creating Facelet for: " + url);
295 }
296
297 String alias = "/" + _removeFirst(url.getFile(), _baseUrl.getFile());
298 try
299 {
300 FaceletHandler h = _compiler.compile(url, alias);
301 DefaultFacelet f = new DefaultFacelet(this, _compiler.createExpressionFactory(), url, alias, alias, h);
302 return f;
303 }
304 catch (FileNotFoundException fnfe)
305 {
306 throw new FileNotFoundException("Facelet " + alias + " not found at: " + url.toExternalForm());
307 }
308 }
309
310
311
312
313
314
315
316
317
318
319 private DefaultFacelet _createViewMetadataFacelet(URL url)
320 throws IOException, FaceletException, FacesException, ELException
321 {
322 if (log.isLoggable(Level.FINE))
323 {
324 log.fine("Creating Facelet used to create View Metadata for: " + url);
325 }
326
327
328
329 String faceletId = "/"+ _removeFirst(url.getFile(), _baseUrl.getFile());
330 String alias = "/viewMetadata" + faceletId;
331 try
332 {
333 FaceletHandler h = _compiler.compileViewMetadata(url, alias);
334 DefaultFacelet f = new DefaultFacelet(this, _compiler.createExpressionFactory(), url, alias,
335 faceletId, h);
336 return f;
337 }
338 catch (FileNotFoundException fnfe)
339 {
340 throw new FileNotFoundException("Facelet " + alias + " not found at: " + url.toExternalForm());
341 }
342
343 }
344
345
346
347
348
349
350
351
352
353
354 private DefaultFacelet _createCompositeComponentMetadataFacelet(URL url)
355 throws IOException, FaceletException, FacesException, ELException
356 {
357 if (log.isLoggable(Level.FINE))
358 {
359 log.fine("Creating Facelet used to create Composite Component Metadata for: " + url);
360 }
361
362
363
364 String alias = "/compositeComponentMetadata/" + _removeFirst(url.getFile(), _baseUrl.getFile());
365 try
366 {
367 FaceletHandler h = _compiler.compileCompositeComponentMetadata(url, alias);
368 DefaultFacelet f = new DefaultFacelet(this, _compiler.createExpressionFactory(), url, alias,
369 alias, h, true);
370 return f;
371 }
372 catch (FileNotFoundException fnfe)
373 {
374 throw new FileNotFoundException("Facelet " + alias + " not found at: " + url.toExternalForm());
375 }
376 }
377
378
379
380
381
382
383 @Override
384 public Facelet getViewMetadataFacelet(String uri) throws IOException
385 {
386 URL url = (URL) _relativeLocations.get(uri);
387 if (url == null)
388 {
389 url = resolveURL(_baseUrl, uri);
390 if (url != null)
391 {
392 Map<String, URL> newLoc = new HashMap<String, URL>(_relativeLocations);
393 newLoc.put(uri, url);
394 _relativeLocations = newLoc;
395 }
396 else
397 {
398 throw new IOException("'" + uri + "' not found.");
399 }
400 }
401 return this.getViewMetadataFacelet(url);
402 }
403
404
405
406
407 @Override
408 public Facelet getViewMetadataFacelet(URL url) throws IOException,
409 FaceletException, FacesException, ELException
410 {
411 return _faceletCache.getViewMetadataFacelet(url);
412 }
413
414
415
416
417
418
419 @Override
420 public Facelet getCompositeComponentMetadataFacelet(String uri) throws IOException
421 {
422 URL url = (URL) _relativeLocations.get(uri);
423 if (url == null)
424 {
425 url = resolveURL(_baseUrl, uri);
426 if (url != null)
427 {
428 Map<String, URL> newLoc = new HashMap<String, URL>(_relativeLocations);
429 newLoc.put(uri, url);
430 _relativeLocations = newLoc;
431 }
432 else
433 {
434 throw new IOException("'" + uri + "' not found.");
435 }
436 }
437 return this.getCompositeComponentMetadataFacelet(url);
438 }
439
440
441
442
443 @Override
444 public Facelet getCompositeComponentMetadataFacelet(URL url) throws IOException,
445 FaceletException, FacesException, ELException
446 {
447 ParameterCheck.notNull("url", url);
448
449 String key = url.toString();
450
451 DefaultFacelet f = _compositeComponentMetadataFacelets.get(key);
452
453 if (f == null || this.needsToBeRefreshed(f))
454 {
455 f = this._createCompositeComponentMetadataFacelet(url);
456 if (_refreshPeriod != NO_CACHE_DELAY)
457 {
458 Map<String, DefaultFacelet> newLoc
459 = new HashMap<String, DefaultFacelet>(_compositeComponentMetadataFacelets);
460 newLoc.put(key, f);
461 _compositeComponentMetadataFacelets = newLoc;
462 }
463 }
464
465 return f;
466 }
467
468
469
470
471
472
473
474
475
476
477
478 private String _removeFirst(String string, String toRemove)
479 {
480
481
482
483 return Pattern.compile(toRemove, Pattern.LITERAL).matcher(string).replaceFirst("");
484 }
485
486 }