RichFaces 4.0 Core: Resources
nbelaevski Jul 2, 2009 11:06 AMHello all,
Jay has asked me to write a short notes on RF 4.0 resources code; so here it is. Suggestions and opinions are highly welcome.
First I've started with LegacyResourceHandlerImpl.java class.
Its functionality is servicing resources using legacy API (InternetResourceBuilder/InternetResource). In order to be able to use these resource in JSF 2.0 tags/#{resource['...']} expression, I've created a LegacyResourceWrapper.java wrapper class - its only functionality is getRequestPath() method that encodes URI for legacy resource.
The main difference in JSF 2.0 and RF 3.3.x resources is that RF resources mostly service (sends HTTP headers and data) themselves. That's so because dynamically generated resources are written directly to OutputStream by ImageIO API; so there's no way to provide InputStream without using some kind of buffering. We have caching services, however not all resources are cacheable by definition. In JSF 2.0, resources servicing is done by ResourceHandler class that reads map containing headers and instance of InputStream class just from resource and then transfers the information to the client.
After measuring memory consumption I've decided to introduce buffering even for non-cached resources in order to increase performance (just think about bytes necessary to hold the whole raster image in memory vs. the same image bytes, but compressed to PNG/GIF; note that image bytes are not reclaimed until the whole image is written and slow clients are highly possible). Additionally, this allows to get more closer to JSF 2.0 resources API. So, here is the updated version of RF Resource implementation ResourceImpl.java
There's a handler that does the job of servicing resources. Resources are searched as classes extending Resource class in TCCL: ResourceHandlerImpl.java
Special interface for the user to plug in his own encoder/decoder for dynamic data (in RF 3.3.x there are two ResourceBuilder implementations - the first that encodes to zip-crypt-base64 and the second that saves data in cache): ResourceCodec.java
Utility class that assists in resources processing stuff and holds the code that both implementations of ResourceHandler share: Util.java
Working example of dynamic image resource: TestResource2.java
Another changes committed are mostly about refactoring Legacy API: switching from HttpServletRequest to ExternalContext. Couple of classes was deprecated, I'd like to discuss their future in the context of PortletBridge also.
Current issues/questions:
1. Are we going to support legacy API - do we need LegacyResourceHandlerImpl?
2. Caching issues - there are some well-known caches (I've experimented with EhCache; JBoss cache is next to try) that do the actual cache fill job in the separate thread (using internal thread pool); however resources generation code may request the stuff bound to the web application thread (e.g. FacesContext; also I have some suspects about TCCL validity). We can cope with the problem by introducing thread pool that will do all cache operations and calling back resource methods in the context of web application thread - JDK 5 has all necessary synchronization primitives to make this very easy to implement; however that does not look like a very good thing for me. Cloning thread context is possible, but also seems a hack. What do you think?
3. In RF 3.3.x there was only one way for the resource in the application cache to be regenerated - to be purged when cache size limit was reached. I suggest that we use "expires" resource data for that; so that resource will expire simultaneosly in HTTP caches and application cache.
4. Password for the crypted resources can be found because we use the same one for the framework data (it has fixed value known to the user; i.e. values of skins parameters) and user data. So, the possibility of defining a set of passwords for the different cases looks like not a bad idea.
5. I haven't set up logging yet, so there are a lot of e.printStackTrace()/TODOs for logging. Are we going to use java.util.Logger or some logging framework, e.g. SLF4J?
Thanks for reading!