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.application.ViewResource;
36 import javax.faces.context.FacesContext;
37 import javax.faces.view.facelets.Facelet;
38 import javax.faces.view.facelets.FaceletCache;
39 import javax.faces.view.facelets.FaceletCacheFactory;
40 import javax.faces.view.facelets.FaceletContext;
41 import javax.faces.view.facelets.FaceletException;
42 import javax.faces.view.facelets.FaceletHandler;
43 import javax.faces.view.facelets.ResourceResolver;
44
45 import org.apache.myfaces.shared.resource.ResourceLoaderUtils;
46 import org.apache.myfaces.view.facelets.AbstractFaceletCache;
47 import org.apache.myfaces.view.facelets.FaceletFactory;
48 import org.apache.myfaces.view.facelets.compiler.Compiler;
49 import org.apache.myfaces.view.facelets.util.ParameterCheck;
50
51
52
53
54
55
56
57 public final class DefaultFaceletFactory extends FaceletFactory
58 {
59 private static final long INFINITE_DELAY = -1;
60 private static final long NO_CACHE_DELAY = 0;
61
62
63 protected final Logger log = Logger.getLogger(DefaultFaceletFactory.class.getName());
64
65 private URL _baseUrl;
66
67 private Compiler _compiler;
68
69
70
71
72
73 private Map<String, DefaultFacelet> _compositeComponentMetadataFacelets;
74
75 private long _refreshPeriod;
76
77 private Map<String, URL> _relativeLocations;
78
79 private javax.faces.view.facelets.ResourceResolver _resolver;
80 private DefaultResourceResolver _defaultResolver;
81
82 private FaceletCache<Facelet> _faceletCache;
83 private AbstractFaceletCache<Facelet> _abstractFaceletCache;
84
85 public DefaultFaceletFactory(Compiler compiler, ResourceResolver resolver) throws IOException
86 {
87 this(compiler, resolver, -1);
88 }
89
90 public DefaultFaceletFactory(Compiler compiler, ResourceResolver resolver, long refreshPeriod)
91 {
92 ParameterCheck.notNull("compiler", compiler);
93 ParameterCheck.notNull("resolver", resolver);
94
95 _compiler = compiler;
96
97
98
99
100
101 _compositeComponentMetadataFacelets = new HashMap<String, DefaultFacelet>();
102
103 _relativeLocations = new HashMap<String, URL>();
104
105 _resolver = resolver;
106 if (_resolver instanceof DefaultResourceResolver)
107 {
108 _defaultResolver = (DefaultResourceResolver) _resolver;
109 }
110
111
112
113 _refreshPeriod = refreshPeriod < 0 ? INFINITE_DELAY : refreshPeriod * 1000;
114
115
116 FaceletCacheFactory cacheFactory
117 = (FaceletCacheFactory) FactoryFinder.getFactory(FactoryFinder.FACELET_CACHE_FACTORY);
118 _faceletCache = (FaceletCache<Facelet>) cacheFactory.getFaceletCache();
119
120 FaceletCache.MemberFactory<Facelet> faceletFactory = new FaceletCache.MemberFactory<Facelet>()
121 {
122 public Facelet newInstance(URL url) throws IOException
123 {
124 return _createFacelet(url);
125 }
126 };
127 FaceletCache.MemberFactory<Facelet> viewMetadataFaceletFactory = new FaceletCache.MemberFactory<Facelet>()
128 {
129 public Facelet newInstance(URL url) throws IOException
130 {
131 return _createViewMetadataFacelet(url);
132 }
133 };
134
135 if (_faceletCache instanceof AbstractFaceletCache)
136 {
137 _abstractFaceletCache = (AbstractFaceletCache<Facelet>) _faceletCache;
138
139 FaceletCache.MemberFactory<Facelet> compositeComponentMetadataFaceletFactory =
140 new FaceletCache.MemberFactory<Facelet>()
141 {
142 public Facelet newInstance(URL url) throws IOException
143 {
144 return _createCompositeComponentMetadataFacelet(url);
145 }
146 };
147
148 try
149 {
150 Method setMemberFactoriesMethod = AbstractFaceletCache.class.getDeclaredMethod("setMemberFactories",
151 new Class[]{FaceletCache.MemberFactory.class, FaceletCache.MemberFactory.class,
152 FaceletCache.MemberFactory.class});
153 setMemberFactoriesMethod.setAccessible(true);
154 setMemberFactoriesMethod.invoke(_faceletCache, faceletFactory, viewMetadataFaceletFactory,
155 compositeComponentMetadataFaceletFactory);
156 }
157 catch (Exception e)
158 {
159 throw new FacesException(
160 "Cannot call setMemberFactories method, Initialization of FaceletCache failed.",
161 e);
162 }
163 }
164 else
165 {
166
167
168
169
170
171 try
172 {
173 Method setMemberFactoriesMethod = FaceletCache.class.getDeclaredMethod("setMemberFactories",
174 new Class[]{FaceletCache.MemberFactory.class, FaceletCache.MemberFactory.class});
175 setMemberFactoriesMethod.setAccessible(true);
176 setMemberFactoriesMethod.invoke(_faceletCache, faceletFactory, viewMetadataFaceletFactory);
177 }
178 catch (Exception e)
179 {
180 throw new FacesException(
181 "Cannot call setMemberFactories method, Initialization of FaceletCache failed.",
182 e);
183 }
184 }
185
186 if (log.isLoggable(Level.FINE))
187 {
188 log.fine("Using ResourceResolver: " + _resolver);
189 log.fine("Using Refresh Period: " + _refreshPeriod);
190 }
191 }
192
193
194
195
196
197
198 public Compiler getCompiler()
199 {
200 return _compiler;
201 }
202
203 private URL getBaseUrl()
204 {
205 if (_baseUrl == null)
206 {
207 _baseUrl = _resolver.resolveUrl("/");
208 }
209 return _baseUrl;
210 }
211
212
213
214
215
216
217 @Override
218 public Facelet getFacelet(FacesContext facesContext, String uri)
219 throws IOException, FaceletException, FacesException, ELException
220 {
221 URL url = (URL) _relativeLocations.get(uri);
222 if (url == null)
223 {
224 url = resolveURL(facesContext, getBaseUrl(), uri);
225 if (url != null)
226 {
227 ViewResource viewResource = (ViewResource) facesContext.getAttributes().get(
228 FaceletFactory.LAST_RESOURCE_RESOLVED);
229 if (viewResource != null)
230 {
231
232
233 }
234 else
235 {
236 Map<String, URL> newLoc = new HashMap<String, URL>(_relativeLocations);
237 newLoc.put(uri, url);
238 _relativeLocations = newLoc;
239 }
240 }
241 else
242 {
243 throw new IOException("'" + uri + "' not found.");
244 }
245 }
246 return this.getFacelet(url);
247 }
248
249
250
251
252
253
254
255
256
257
258
259
260
261 @Override
262 public Facelet getFacelet(URL url) throws IOException, FaceletException, FacesException, ELException
263 {
264 return _faceletCache.getFacelet(url);
265 }
266
267
268 @Override
269 public Facelet getFacelet(FaceletContext ctx, URL url)
270 throws IOException, FaceletException, FacesException, ELException
271 {
272 if (_abstractFaceletCache != null)
273 {
274 return _abstractFaceletCache.getFacelet(ctx, url);
275 }
276 else
277 {
278 return _faceletCache.getFacelet(url);
279 }
280 }
281
282 public long getRefreshPeriod()
283 {
284 return _refreshPeriod;
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 public URL resolveURL(FacesContext context, URL source, String path) throws IOException
301 {
302 if (path.startsWith("/"))
303 {
304 context.getAttributes().put(LAST_RESOURCE_RESOLVED, null);
305 URL url = resolveURL(context, path);
306 if (url == null)
307 {
308 throw new FileNotFoundException(path + " Not Found in ExternalContext as a Resource");
309 }
310 return url;
311 }
312 else
313 {
314 return new URL(source, path);
315 }
316 }
317
318
319
320
321
322
323
324
325 protected boolean needsToBeRefreshed(DefaultFacelet facelet)
326 {
327
328 if (_refreshPeriod == NO_CACHE_DELAY)
329 {
330 return true;
331 }
332
333
334 if (_refreshPeriod == INFINITE_DELAY)
335 {
336 return false;
337 }
338
339 long target = facelet.getCreateTime() + _refreshPeriod;
340 if (System.currentTimeMillis() > target)
341 {
342
343
344 URLConnection conn = null;
345 try
346 {
347 conn = facelet.getSource().openConnection();
348 long lastModified = ResourceLoaderUtils.getResourceLastModified(conn);
349
350 return lastModified == 0 || lastModified > target;
351 }
352 catch (IOException e)
353 {
354 throw new FaceletException("Error Checking Last Modified for " + facelet.getAlias(), e);
355 }
356 finally
357 {
358 if (conn != null)
359 {
360 try
361 {
362 conn.getInputStream().close();
363 }
364 catch (Exception e)
365 {
366
367 }
368 }
369 }
370 }
371
372 return false;
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386 private DefaultFacelet _createFacelet(URL url) throws IOException, FaceletException, FacesException, ELException
387 {
388 if (log.isLoggable(Level.FINE))
389 {
390 log.fine("Creating Facelet for: " + url);
391 }
392
393 String alias = "/" + _removeFirst(url.getFile(), getBaseUrl().getFile());
394 try
395 {
396 FaceletHandler h = _compiler.compile(url, alias);
397 DefaultFacelet f = new DefaultFacelet(this, _compiler.createExpressionFactory(), url, alias, alias, h);
398 return f;
399 }
400 catch (FileNotFoundException fnfe)
401 {
402 throw new FileNotFoundException("Facelet " + alias + " not found at: " + url.toExternalForm());
403 }
404 }
405
406
407
408
409
410
411
412
413
414
415 private DefaultFacelet _createViewMetadataFacelet(URL url)
416 throws IOException, FaceletException, FacesException, ELException
417 {
418 if (log.isLoggable(Level.FINE))
419 {
420 log.fine("Creating Facelet used to create View Metadata for: " + url);
421 }
422
423
424
425 String faceletId = "/"+ _removeFirst(url.getFile(), getBaseUrl().getFile());
426 String alias = "/viewMetadata" + faceletId;
427 try
428 {
429 FaceletHandler h = _compiler.compileViewMetadata(url, alias);
430 DefaultFacelet f = new DefaultFacelet(this, _compiler.createExpressionFactory(), url, alias,
431 faceletId, h);
432 return f;
433 }
434 catch (FileNotFoundException fnfe)
435 {
436 throw new FileNotFoundException("Facelet " + alias + " not found at: " + url.toExternalForm());
437 }
438
439 }
440
441
442
443
444
445
446
447
448
449
450 private DefaultFacelet _createCompositeComponentMetadataFacelet(URL url)
451 throws IOException, FaceletException, FacesException, ELException
452 {
453 if (log.isLoggable(Level.FINE))
454 {
455 log.fine("Creating Facelet used to create Composite Component Metadata for: " + url);
456 }
457
458
459
460 String alias = "/compositeComponentMetadata/" + _removeFirst(url.getFile(), getBaseUrl().getFile());
461 try
462 {
463 FaceletHandler h = _compiler.compileCompositeComponentMetadata(url, alias);
464 DefaultFacelet f = new DefaultFacelet(this, _compiler.createExpressionFactory(), url, alias,
465 alias, h, true);
466 return f;
467 }
468 catch (FileNotFoundException fnfe)
469 {
470 throw new FileNotFoundException("Facelet " + alias + " not found at: " + url.toExternalForm());
471 }
472 }
473
474
475
476
477
478
479 @Override
480 public Facelet getViewMetadataFacelet(FacesContext facesContext, String uri)
481 throws IOException
482 {
483 URL url = (URL) _relativeLocations.get(uri);
484 if (url == null)
485 {
486 url = resolveURL(facesContext, getBaseUrl(), uri);
487 ViewResource viewResource = (ViewResource) facesContext.getAttributes().get(
488 FaceletFactory.LAST_RESOURCE_RESOLVED);
489 if (url != null)
490 {
491 if (viewResource != null)
492 {
493
494
495 }
496 else
497 {
498 Map<String, URL> newLoc = new HashMap<String, URL>(_relativeLocations);
499 newLoc.put(uri, url);
500 _relativeLocations = newLoc;
501 }
502 }
503 else
504 {
505 throw new IOException("'" + uri + "' not found.");
506 }
507 }
508 return this.getViewMetadataFacelet(url);
509 }
510
511
512
513
514 @Override
515 public Facelet getViewMetadataFacelet(URL url) throws IOException,
516 FaceletException, FacesException, ELException
517 {
518 if (_abstractFaceletCache != null)
519 {
520 return _abstractFaceletCache.getViewMetadataFacelet(url);
521 }
522 else
523 {
524 return _faceletCache.getViewMetadataFacelet(url);
525 }
526 }
527
528
529
530
531
532
533 @Override
534 public Facelet getCompositeComponentMetadataFacelet(FacesContext facesContext, String uri)
535 throws IOException
536 {
537 URL url = (URL) _relativeLocations.get(uri);
538 if (url == null)
539 {
540 url = resolveURL(facesContext, getBaseUrl(), uri);
541 ViewResource viewResource = (ViewResource) facesContext.getAttributes().get(
542 FaceletFactory.LAST_RESOURCE_RESOLVED);
543 if (url != null)
544 {
545 if (viewResource != null)
546 {
547
548
549 }
550 else
551 {
552 Map<String, URL> newLoc = new HashMap<String, URL>(_relativeLocations);
553 newLoc.put(uri, url);
554 _relativeLocations = newLoc;
555 }
556 }
557 else
558 {
559 throw new IOException("'" + uri + "' not found.");
560 }
561 }
562 return this.getCompositeComponentMetadataFacelet(url);
563 }
564
565
566
567
568 @Override
569 public Facelet getCompositeComponentMetadataFacelet(URL url) throws IOException,
570 FaceletException, FacesException, ELException
571 {
572 if (_abstractFaceletCache != null)
573 {
574 return _abstractFaceletCache.getCompositeComponentMetadataFacelet(url);
575 }
576 else
577 {
578 ParameterCheck.notNull("url", url);
579
580 String key = url.toString();
581
582 DefaultFacelet f = _compositeComponentMetadataFacelets.get(key);
583
584 if (f == null || this.needsToBeRefreshed(f))
585 {
586 f = this._createCompositeComponentMetadataFacelet(url);
587 if (_refreshPeriod != NO_CACHE_DELAY)
588 {
589 Map<String, DefaultFacelet> newLoc
590 = new HashMap<String, DefaultFacelet>(_compositeComponentMetadataFacelets);
591 newLoc.put(key, f);
592 _compositeComponentMetadataFacelets = newLoc;
593 }
594 }
595 return f;
596 }
597 }
598
599 private URL resolveURL(FacesContext context, String path)
600 {
601 if (_defaultResolver != null)
602 {
603 return _defaultResolver.resolveUrl(context, path);
604 }
605 else
606 {
607 return _resolver.resolveUrl(path);
608 }
609 }
610
611 public Facelet compileComponentFacelet(String taglibURI, String tagName, Map<String,Object> attributes)
612 {
613 FaceletHandler handler = _compiler.compileComponent(taglibURI, tagName, attributes);
614 String alias = "/component/oamf:"+tagName;
615 return new DefaultFacelet(this, _compiler.createExpressionFactory(), getBaseUrl(), alias, alias, handler);
616 }
617
618
619
620
621
622
623
624
625
626
627
628 private String _removeFirst(String string, String toRemove)
629 {
630
631
632
633 return Pattern.compile(toRemove, Pattern.LITERAL).matcher(string).replaceFirst("");
634 }
635
636 }